From 19f4f4168157e992c034c04297e407a29c237b8a Mon Sep 17 00:00:00 2001 From: fintarin Date: Thu, 27 Jul 2023 14:19:35 +0300 Subject: [PATCH] Add Inf and Indeterminate --- include/fintamath/core/MathObjectTypes.hpp | 30 ++++---- .../literals/constants/Indeterminate.hpp | 22 ++++++ include/fintamath/literals/constants/Inf.hpp | 22 ++++++ .../fintamath/literals/constants/NegInf.hpp | 22 ++++++ src/fintamath/config/ParserConfig.cpp | 6 ++ src/fintamath/expressions/Expression.cpp | 2 +- src/fintamath/expressions/ExpressionUtils.cpp | 2 + src/fintamath/expressions/IExpression.cpp | 1 + .../expressions/binary/DivExpression.cpp | 33 ++++++--- .../expressions/binary/DivExpression.hpp | 2 +- .../expressions/binary/PowExpression.cpp | 64 +++++++++++----- .../expressions/binary/PowExpression.hpp | 2 +- .../interfaces/IBinaryExpression.cpp | 9 +++ .../interfaces/IPolynomExpression.cpp | 6 ++ .../interfaces/IUnaryExpression.cpp | 9 +++ .../expressions/polynomial/AddExpression.cpp | 20 ++++- .../expressions/polynomial/AddExpression.hpp | 2 +- .../expressions/polynomial/MulExpression.cpp | 26 ++++++- .../expressions/polynomial/MulExpression.hpp | 2 +- .../expressions/unary/NegExpression.cpp | 16 ++++ .../expressions/unary/NegExpression.hpp | 2 + src/fintamath/functions/arithmetic/Div.cpp | 10 +++ src/fintamath/functions/powers/Pow.cpp | 5 ++ .../literals/constants/Indeterminate.cpp | 11 +++ src/fintamath/literals/constants/Inf.cpp | 11 +++ src/fintamath/literals/constants/NegInf.cpp | 11 +++ tests/src/expressions/ExpressionTests.cpp | 74 +++++++++++++++++-- tests/src/functions/powers/PowFTests.cpp | 3 +- tests/src/functions/powers/PowTests.cpp | 3 +- tests/src/parser/ParserTests.cpp | 11 ++- 30 files changed, 373 insertions(+), 66 deletions(-) create mode 100644 include/fintamath/literals/constants/Indeterminate.hpp create mode 100644 include/fintamath/literals/constants/Inf.hpp create mode 100644 include/fintamath/literals/constants/NegInf.hpp create mode 100644 src/fintamath/literals/constants/Indeterminate.cpp create mode 100644 src/fintamath/literals/constants/Inf.cpp create mode 100644 src/fintamath/literals/constants/NegInf.cpp diff --git a/include/fintamath/core/MathObjectTypes.hpp b/include/fintamath/core/MathObjectTypes.hpp index 78c2bb6cc..ca54678f7 100644 --- a/include/fintamath/core/MathObjectTypes.hpp +++ b/include/fintamath/core/MathObjectTypes.hpp @@ -64,6 +64,9 @@ enum class MathObjectType : MathObjectTypeId { Pi, True, False, + Inf, + NegInf, + Indeterminate, IFunction = 11000, @@ -144,19 +147,19 @@ class MathObjectBoundTypeIds { using Type = MathObjectType; static std::unordered_map ids{ - {Id(Type::IMathObject), Id(Type::None)}, // - {Id(Type::IArithmetic), Id(Type::ILiteral)}, // - {Id(Type::IExpression), Id(Type::IComparable)}, // - {Id(Type::IUnaryExpression), Id(Type::IBinaryExpression)}, // - {Id(Type::IBinaryExpression), Id(Type::IPolynomExpression)}, // - {Id(Type::IPolynomExpression), Id(Type::IComparable)}, // - {Id(Type::IComparable), Id(Type::ILiteral)}, // - {Id(Type::INumber), Id(Type::ILiteral)}, // - {Id(Type::IInteger), Id(Type::ILiteral)}, // - {Id(Type::ILiteral), Id(Type::IFunction)}, // - {Id(Type::IConstant), Id(Type::IFunction)}, // - {Id(Type::IFunction), Id(Type::None)}, // - {Id(Type::IOperator), Id(Type::None)}, // + {Id(Type::IMathObject), Id(Type::None)}, + {Id(Type::IArithmetic), Id(Type::ILiteral)}, + {Id(Type::IExpression), Id(Type::IComparable)}, + {Id(Type::IUnaryExpression), Id(Type::IBinaryExpression)}, + {Id(Type::IBinaryExpression), Id(Type::IPolynomExpression)}, + {Id(Type::IPolynomExpression), Id(Type::IComparable)}, + {Id(Type::IComparable), Id(Type::ILiteral)}, + {Id(Type::INumber), Id(Type::ILiteral)}, + {Id(Type::IInteger), Id(Type::ILiteral)}, + {Id(Type::ILiteral), Id(Type::IFunction)}, + {Id(Type::IConstant), Id(Type::IFunction)}, + {Id(Type::IFunction), Id(Type::None)}, + {Id(Type::IOperator), Id(Type::None)}, }; return ids; @@ -166,6 +169,7 @@ class MathObjectBoundTypeIds { inline bool isBaseOf(size_t toTypeId, size_t fromTypeId) { if (auto toTypeBoundaries = MathObjectBoundTypeIds::get().find(toTypeId); toTypeBoundaries != MathObjectBoundTypeIds::get().end()) { + return fromTypeId >= toTypeBoundaries->first && fromTypeId < toTypeBoundaries->second; } diff --git a/include/fintamath/literals/constants/Indeterminate.hpp b/include/fintamath/literals/constants/Indeterminate.hpp new file mode 100644 index 000000000..f7206bca1 --- /dev/null +++ b/include/fintamath/literals/constants/Indeterminate.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/numbers/INumber.hpp" + +namespace fintamath { + +class Indeterminate : public IConstantCRTP { +public: + std::string toString() const override { + return "Indeterminate"; + } + + static MathObjectTypeId getTypeIdStatic() { + return MathObjectTypeId(MathObjectType::Indeterminate); + } + +protected: + std::unique_ptr call() const override; +}; + +} diff --git a/include/fintamath/literals/constants/Inf.hpp b/include/fintamath/literals/constants/Inf.hpp new file mode 100644 index 000000000..a32955e62 --- /dev/null +++ b/include/fintamath/literals/constants/Inf.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/numbers/INumber.hpp" + +namespace fintamath { + +class Inf : public IConstantCRTP { +public: + std::string toString() const override { + return "Inf"; + } + + static MathObjectTypeId getTypeIdStatic() { + return MathObjectTypeId(MathObjectType::Inf); + } + +protected: + std::unique_ptr call() const override; +}; + +} diff --git a/include/fintamath/literals/constants/NegInf.hpp b/include/fintamath/literals/constants/NegInf.hpp new file mode 100644 index 000000000..46e6fa04c --- /dev/null +++ b/include/fintamath/literals/constants/NegInf.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/numbers/INumber.hpp" + +namespace fintamath { + +class NegInf : public IConstantCRTP { +public: + std::string toString() const override { + return "-Inf"; + } + + static MathObjectTypeId getTypeIdStatic() { + return MathObjectTypeId(MathObjectType::NegInf); + } + +protected: + std::unique_ptr call() const override; +}; + +} diff --git a/src/fintamath/config/ParserConfig.cpp b/src/fintamath/config/ParserConfig.cpp index eb7ce4347..0a4cb88e4 100644 --- a/src/fintamath/config/ParserConfig.cpp +++ b/src/fintamath/config/ParserConfig.cpp @@ -65,8 +65,11 @@ #include "fintamath/literals/constants/E.hpp" #include "fintamath/literals/constants/False.hpp" #include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" #include "fintamath/literals/constants/Pi.hpp" #include "fintamath/literals/constants/True.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/IInteger.hpp" #include "fintamath/numbers/INumber.hpp" #include "fintamath/numbers/Integer.hpp" @@ -165,6 +168,9 @@ struct ParserConfig { IConstant::registerType(); IConstant::registerType(); IConstant::registerType(); + IConstant::registerType(); + IConstant::registerType(); + IConstant::registerType(); IFunction::registerType(); IFunction::registerType(); diff --git a/src/fintamath/expressions/Expression.cpp b/src/fintamath/expressions/Expression.cpp index 249762f86..bd61f9e00 100644 --- a/src/fintamath/expressions/Expression.cpp +++ b/src/fintamath/expressions/Expression.cpp @@ -459,7 +459,7 @@ void Expression::validateFunctionArgs(const std::shared_ptr &func, co else if (const auto childConst = cast(arg)) { const MathObjectTypeId childTypeId = childConst->getReturnTypeId(); - if (!isBaseOf(typeId, childTypeId)) { + if (!isBaseOf(typeId, childTypeId) && !isBaseOf(childTypeId, typeId)) { throw InvalidInputFunctionException(func->toString(), argumentVectorToStringVector(args)); } } diff --git a/src/fintamath/expressions/ExpressionUtils.cpp b/src/fintamath/expressions/ExpressionUtils.cpp index 0b3b95d5c..e890bbaad 100644 --- a/src/fintamath/expressions/ExpressionUtils.cpp +++ b/src/fintamath/expressions/ExpressionUtils.cpp @@ -4,7 +4,9 @@ #include "fintamath/expressions/IExpression.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/literals/constants/NegInf.hpp" #include "fintamath/numbers/Rational.hpp" #include "fintamath/numbers/Real.hpp" diff --git a/src/fintamath/expressions/IExpression.cpp b/src/fintamath/expressions/IExpression.cpp index a2728a2f5..c945ea674 100644 --- a/src/fintamath/expressions/IExpression.cpp +++ b/src/fintamath/expressions/IExpression.cpp @@ -5,6 +5,7 @@ #include "fintamath/functions/other/Index.hpp" #include "fintamath/literals/Variable.hpp" #include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/INumber.hpp" #include "fintamath/numbers/Real.hpp" diff --git a/src/fintamath/expressions/binary/DivExpression.cpp b/src/fintamath/expressions/binary/DivExpression.cpp index 6db9ae27d..8d5b4ec2f 100644 --- a/src/fintamath/expressions/binary/DivExpression.cpp +++ b/src/fintamath/expressions/binary/DivExpression.cpp @@ -8,6 +8,9 @@ #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/arithmetic/Sub.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" #include "fintamath/numbers/Rational.hpp" @@ -28,16 +31,16 @@ std::string DivExpression::toString() const { DivExpression::SimplifyFunctionsVector DivExpression::getFunctionsForPreSimplify() const { static const DivExpression::SimplifyFunctionsVector simplifyFunctions = { - &DivExpression::zeroSimplify, // - &DivExpression::divSimplify, // - &DivExpression::mulSimplify, // + &DivExpression::constSimplify, // + &DivExpression::divSimplify, // + &DivExpression::mulSimplify, // }; return simplifyFunctions; } DivExpression::SimplifyFunctionsVector DivExpression::getFunctionsForPostSimplify() const { static const DivExpression::SimplifyFunctionsVector simplifyFunctions = { - &DivExpression::zeroSimplify, // + &DivExpression::constSimplify, // &DivExpression::negSimplify, // &DivExpression::numSimplify, // &DivExpression::divSimplify, // @@ -49,19 +52,29 @@ DivExpression::SimplifyFunctionsVector DivExpression::getFunctionsForPostSimplif return simplifyFunctions; } -ArgumentPtr DivExpression::zeroSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { +ArgumentPtr DivExpression::constSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { + if ((*lhs == Integer(0) || is(lhs) || is(lhs)) && + (*rhs == Integer(0) || is(rhs) || is(rhs))) { + + return Indeterminate().clone(); + } + + if (*lhs == Integer(0)) { + return lhs; + } + if (*rhs == Integer(0)) { - throw UndefinedBinaryOperatorException(Div().toString(), lhs->toString(), rhs->toString()); + return Inf().clone(); + } + + if (is(rhs) || is(rhs)) { + return Integer(0).clone(); } return {}; } ArgumentPtr DivExpression::numSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { - if (*lhs == Integer(0)) { - return lhs; - } - static const Integer one = 1; if (Div().doArgsMatch({one, *rhs})) { diff --git a/src/fintamath/expressions/binary/DivExpression.hpp b/src/fintamath/expressions/binary/DivExpression.hpp index 5d3f35c95..a3720d937 100644 --- a/src/fintamath/expressions/binary/DivExpression.hpp +++ b/src/fintamath/expressions/binary/DivExpression.hpp @@ -21,7 +21,7 @@ class DivExpression : public IBinaryExpressionCRTP { SimplifyFunctionsVector getFunctionsForPostSimplify() const override; private: - static ArgumentPtr zeroSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); + static ArgumentPtr constSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); static ArgumentPtr numSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); diff --git a/src/fintamath/expressions/binary/PowExpression.cpp b/src/fintamath/expressions/binary/PowExpression.cpp index 894c6f2fa..7166d6fcf 100644 --- a/src/fintamath/expressions/binary/PowExpression.cpp +++ b/src/fintamath/expressions/binary/PowExpression.cpp @@ -9,6 +9,9 @@ #include "fintamath/functions/powers/Pow.hpp" #include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" #include "fintamath/numbers/Rational.hpp" @@ -79,15 +82,15 @@ ArgumentPtr PowExpression::preciseSimplify() const { PowExpression::SimplifyFunctionsVector PowExpression::getFunctionsForPreSimplify() const { static const PowExpression::SimplifyFunctionsVector simplifyFunctions = { - &PowExpression::negSimplify, // - &PowExpression::powSimplify, // + &PowExpression::negSimplify, // + &PowExpression::powSimplify, // }; return simplifyFunctions; } PowExpression::SimplifyFunctionsVector PowExpression::getFunctionsForPostSimplify() const { static const PowExpression::SimplifyFunctionsVector simplifyFunctions = { - &PowExpression::numSimplify, // + &PowExpression::constSimplify, // &PowExpression::polynomSimplify, // &PowExpression::negSimplify, // &PowExpression::powSimplify, // @@ -200,32 +203,55 @@ ArgumentPtr PowExpression::powSimplify(const IFunction & /*func*/, const Argumen return res; } -ArgumentPtr PowExpression::numSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { - auto lhsInt = cast(lhs); - auto rhsInt = cast(rhs); +ArgumentPtr PowExpression::constSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { + if (*rhs == Integer(1)) { + return lhs; + } - if (rhsInt) { - if (*rhsInt == 0) { - return std::make_shared(1); - } + if (*rhs == Integer(-1)) { + ArgumentPtr divLhs = Integer(1).clone(); + ArgumentPtr divRhs = lhs; + return makeExpr(Div(), divLhs, divRhs); + } + + if (const auto rhsComp = cast(rhs); is(rhs) || (rhsComp && *rhsComp < Integer(0))) { + ArgumentPtr divLhs = Integer(1).clone(); + ArgumentPtr divRhs = makeExpr(Pow(), lhs, makeExpr(Neg(), rhs)); + return makeExpr(Div(), divLhs, divRhs); + } + + if (is(lhs)) { + ArgumentPtr mulLhs = makeExpr(Pow(), Integer(-1).clone(), rhs); + ArgumentPtr mulRhs = makeExpr(Pow(), Inf().clone(), rhs); + return makeExpr(Mul(), mulLhs, mulRhs); + } - if (*rhsInt == 1 || (lhsInt && *lhsInt == 1)) { - return lhs; + if (*lhs == Integer(0)) { + if (*rhs == Integer(0)) { + return Indeterminate().clone(); } - if (*rhsInt == -1) { - ArgumentPtr res = makeExpr(Div(), std::make_shared(1), lhs); - return res; + return lhs; + } + + if (*lhs == Integer(1)) { + if (is(rhs)) { + return Indeterminate().clone(); } + + return lhs; } - if (lhsInt && *lhsInt == 0) { + if (is(lhs)) { + if (*rhs == Integer(0)) { + return Indeterminate().clone(); + } + return lhs; } - if (const auto rhsComp = cast(rhs); rhsComp && *rhsComp < Integer(0)) { - ArgumentPtr res = makeExpr(Div(), std::make_shared(1), makeExpr(Pow(), lhs, makeExpr(Neg(), rhs))); - return res; + if (*rhs == Integer(0)) { + return Integer(1).clone(); } return {}; diff --git a/src/fintamath/expressions/binary/PowExpression.hpp b/src/fintamath/expressions/binary/PowExpression.hpp index 58a835809..f6e4cfbd8 100644 --- a/src/fintamath/expressions/binary/PowExpression.hpp +++ b/src/fintamath/expressions/binary/PowExpression.hpp @@ -37,7 +37,7 @@ class PowExpression : public IBinaryExpressionCRTP { static ArgumentPtr powSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); - static ArgumentPtr numSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); + static ArgumentPtr constSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); static ArgumentPtr polynomSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); diff --git a/src/fintamath/expressions/interfaces/IBinaryExpression.cpp b/src/fintamath/expressions/interfaces/IBinaryExpression.cpp index abfa28b35..1518eb3b4 100644 --- a/src/fintamath/expressions/interfaces/IBinaryExpression.cpp +++ b/src/fintamath/expressions/interfaces/IBinaryExpression.cpp @@ -1,6 +1,7 @@ #include "fintamath/expressions/interfaces/IBinaryExpression.hpp" #include "fintamath/expressions/ExpressionUtils.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" namespace fintamath { @@ -25,6 +26,10 @@ ArgumentPtr IBinaryExpression::preSimplify() const { preSimplifyChild(simpl->lhsChild); preSimplifyChild(simpl->rhsChild); + if (is(simpl->lhsChild) || is(simpl->rhsChild)) { + return Indeterminate().clone(); + } + ArgumentPtr res = simpl->useSimplifyFunctions(getFunctionsForPreSimplify()); if (res && *res != *simpl) { @@ -40,6 +45,10 @@ ArgumentPtr IBinaryExpression::postSimplify() const { postSimplifyChild(simpl->lhsChild); postSimplifyChild(simpl->rhsChild); + if (is(simpl->lhsChild) || is(simpl->rhsChild)) { + return Indeterminate().clone(); + } + if (ArgumentPtr res = callFunction(*simpl->func, {simpl->lhsChild, simpl->rhsChild})) { return res; } diff --git a/src/fintamath/expressions/interfaces/IPolynomExpression.cpp b/src/fintamath/expressions/interfaces/IPolynomExpression.cpp index 2b4d26054..44c65ac86 100644 --- a/src/fintamath/expressions/interfaces/IPolynomExpression.cpp +++ b/src/fintamath/expressions/interfaces/IPolynomExpression.cpp @@ -7,6 +7,7 @@ #include "fintamath/functions/IOperator.hpp" #include "fintamath/literals/Variable.hpp" #include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" namespace fintamath { @@ -92,6 +93,11 @@ void IPolynomExpression::simplifyRec(bool isPostSimplify) { const ArgumentPtr &lhs = children[i - 1]; const ArgumentPtr &rhs = children[i]; + if (is(lhs) || is(rhs)) { + children = {Indeterminate().clone()}; + break; + } + ArgumentPtr res; bool isResSimplified = false; diff --git a/src/fintamath/expressions/interfaces/IUnaryExpression.cpp b/src/fintamath/expressions/interfaces/IUnaryExpression.cpp index ae4474ed3..2c624ff20 100644 --- a/src/fintamath/expressions/interfaces/IUnaryExpression.cpp +++ b/src/fintamath/expressions/interfaces/IUnaryExpression.cpp @@ -2,6 +2,7 @@ #include "fintamath/core/IComparable.hpp" #include "fintamath/expressions/ExpressionUtils.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" namespace fintamath { @@ -44,6 +45,10 @@ ArgumentPtr IUnaryExpression::preSimplify() const { auto simpl = cast(clone()); preSimplifyChild(simpl->child); + if (is(simpl->child)) { + return Indeterminate().clone(); + } + ArgumentPtr res = simpl->useSimplifyFunctions(getFunctionsForPreSimplify()); if (res && *res != *simpl) { @@ -58,6 +63,10 @@ ArgumentPtr IUnaryExpression::postSimplify() const { auto simpl = cast(clone()); postSimplifyChild(simpl->child); + if (is(simpl->child)) { + return Indeterminate().clone(); + } + if (ArgumentPtr res = callFunction(*simpl->func, {simpl->child})) { return res; } diff --git a/src/fintamath/expressions/polynomial/AddExpression.cpp b/src/fintamath/expressions/polynomial/AddExpression.cpp index d65eec718..6c626da0a 100644 --- a/src/fintamath/expressions/polynomial/AddExpression.cpp +++ b/src/fintamath/expressions/polynomial/AddExpression.cpp @@ -10,6 +10,9 @@ #include "fintamath/functions/powers/Pow.hpp" #include "fintamath/literals/Variable.hpp" #include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/Rational.hpp" namespace fintamath { @@ -73,7 +76,7 @@ AddExpression::SimplifyFunctionsVector AddExpression::getFunctionsForPreSimplify &AddExpression::simplifyNegations, // &AddExpression::simplifyCallFunction, // &AddExpression::sumDivisions, // - &AddExpression::simplifyNumbers, // + &AddExpression::simplifyConst, // &AddExpression::sumRates, // &AddExpression::simplifyLogarithms, // &AddExpression::simplifyMulLogarithms, // @@ -83,7 +86,7 @@ AddExpression::SimplifyFunctionsVector AddExpression::getFunctionsForPreSimplify AddExpression::SimplifyFunctionsVector AddExpression::getFunctionsForPostSimplify() const { static const AddExpression::SimplifyFunctionsVector simplifyFunctions = { - &AddExpression::simplifyNumbers, // + &AddExpression::simplifyConst, // &AddExpression::sumRates, // &AddExpression::simplifyLogarithms, // &AddExpression::simplifyMulLogarithms, // @@ -91,15 +94,24 @@ AddExpression::SimplifyFunctionsVector AddExpression::getFunctionsForPostSimplif return simplifyFunctions; } -ArgumentPtr AddExpression::simplifyNumbers(const IFunction & /*func*/, const ArgumentPtr &lhsChild, - const ArgumentPtr &rhsChild) { +ArgumentPtr AddExpression::simplifyConst(const IFunction & /*func*/, const ArgumentPtr &lhsChild, + const ArgumentPtr &rhsChild) { if (*lhsChild == Integer(0)) { return rhsChild; } + if (*rhsChild == Integer(0)) { return lhsChild; } + if (is(lhsChild) && is(rhsChild)) { + return Indeterminate().clone(); + } + + if (is(lhsChild) || is(lhsChild)) { + return lhsChild; + } + return {}; } diff --git a/src/fintamath/expressions/polynomial/AddExpression.hpp b/src/fintamath/expressions/polynomial/AddExpression.hpp index 213867a67..d5674e09d 100644 --- a/src/fintamath/expressions/polynomial/AddExpression.hpp +++ b/src/fintamath/expressions/polynomial/AddExpression.hpp @@ -31,7 +31,7 @@ class AddExpression : public IPolynomExpressionCRTP { int comparator(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const override; private: - static ArgumentPtr simplifyNumbers(const IFunction &func, const ArgumentPtr &lhsChild, const ArgumentPtr &rhsChild); + static ArgumentPtr simplifyConst(const IFunction &func, const ArgumentPtr &lhsChild, const ArgumentPtr &rhsChild); static ArgumentPtr simplifyCallFunction(const IFunction &func, const ArgumentPtr &lhsChild, const ArgumentPtr &rhsChild); diff --git a/src/fintamath/expressions/polynomial/MulExpression.cpp b/src/fintamath/expressions/polynomial/MulExpression.cpp index 744f9674b..c4f836d3a 100644 --- a/src/fintamath/expressions/polynomial/MulExpression.cpp +++ b/src/fintamath/expressions/polynomial/MulExpression.cpp @@ -10,6 +10,9 @@ #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/powers/Pow.hpp" #include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" #include "fintamath/numbers/Rational.hpp" @@ -56,11 +59,11 @@ std::string MulExpression::operatorChildToString(const ArgumentPtr &inChild, con MulExpression::SimplifyFunctionsVector MulExpression::getFunctionsForPreSimplify() const { static const MulExpression::SimplifyFunctionsVector simplifyFunctions = { + &MulExpression::simplifyConst, // &MulExpression::simplifyCallFunction, // &MulExpression::simplifyRationals, // &MulExpression::simplifyDivisions, // &MulExpression::simplifyPowers, // - &MulExpression::simplifyNumbers, // &MulExpression::simplifyNegations, // }; return simplifyFunctions; @@ -68,10 +71,10 @@ MulExpression::SimplifyFunctionsVector MulExpression::getFunctionsForPreSimplify MulExpression::SimplifyFunctionsVector MulExpression::getFunctionsForPostSimplify() const { static const MulExpression::SimplifyFunctionsVector simplifyFunctions = { + &MulExpression::simplifyConst, // &MulExpression::mulPolynoms, // &MulExpression::simplifyDivisions, // &MulExpression::simplifyPowers, // - &MulExpression::simplifyNumbers, // &MulExpression::simplifyNegations, // }; return simplifyFunctions; @@ -86,8 +89,23 @@ std::pair MulExpression::getRateValuePair(const Argume return {std::make_shared(1), rhsChild}; } -ArgumentPtr MulExpression::simplifyNumbers(const IFunction & /*func*/, const ArgumentPtr &lhsChild, - const ArgumentPtr &rhsChild) { +ArgumentPtr MulExpression::simplifyConst(const IFunction & /*func*/, const ArgumentPtr &lhsChild, + const ArgumentPtr &rhsChild) { + + if (*lhsChild == Integer(0) && (is(rhsChild) || is(rhsChild))) { + return Indeterminate().clone(); + } + + if (is(lhsChild) && is(rhsChild)) { + return lhsChild; + } + + if (is(rhsChild) || is(rhsChild)) { + if (const auto lhsNum = cast(lhsChild)) { + return *lhsNum < Integer(0) ? makeExpr(Neg(), rhsChild) : rhsChild; + } + } + if (*lhsChild == Integer(0)) { return lhsChild; } diff --git a/src/fintamath/expressions/polynomial/MulExpression.hpp b/src/fintamath/expressions/polynomial/MulExpression.hpp index 57dfb5aac..ce947cc63 100644 --- a/src/fintamath/expressions/polynomial/MulExpression.hpp +++ b/src/fintamath/expressions/polynomial/MulExpression.hpp @@ -23,7 +23,7 @@ class MulExpression : public IPolynomExpressionCRTP { bool isTermsOrderInversed() const override; private: - static ArgumentPtr simplifyNumbers(const IFunction &func, const ArgumentPtr &lhsChild, const ArgumentPtr &rhsChild); + static ArgumentPtr simplifyConst(const IFunction &func, const ArgumentPtr &lhsChild, const ArgumentPtr &rhsChild); static ArgumentPtr simplifyRationals(const IFunction &func, const ArgumentPtr &lhsChild, const ArgumentPtr &rhsChild); diff --git a/src/fintamath/expressions/unary/NegExpression.cpp b/src/fintamath/expressions/unary/NegExpression.cpp index 17fc6bdb6..3e7fe712f 100644 --- a/src/fintamath/expressions/unary/NegExpression.cpp +++ b/src/fintamath/expressions/unary/NegExpression.cpp @@ -6,6 +6,8 @@ #include "fintamath/functions/arithmetic/Mul.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/logarithms/Log.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" namespace fintamath { @@ -14,6 +16,7 @@ NegExpression::NegExpression(const ArgumentPtr &inChild) : IUnaryExpressionCRTP( NegExpression::SimplifyFunctionsVector NegExpression::getFunctionsForPreSimplify() const { static const NegExpression::SimplifyFunctionsVector simplifyFunctions = { + &NegExpression::simplifyConst, // &NegExpression::callNegFunction, // &NegExpression::simplifyNestedNeg, // }; @@ -22,6 +25,7 @@ NegExpression::SimplifyFunctionsVector NegExpression::getFunctionsForPreSimplify NegExpression::SimplifyFunctionsVector NegExpression::getFunctionsForPostSimplify() const { static const NegExpression::SimplifyFunctionsVector simplifyFunctions = { + &NegExpression::simplifyConst, // &NegExpression::simplifyNegatable, // &NegExpression::simplifyNestedNeg, // }; @@ -79,4 +83,16 @@ ArgumentPtr NegExpression::simplifyNestedNeg(const IFunction & /*func*/, const A return {}; } +ArgumentPtr NegExpression::simplifyConst(const IFunction & /*func*/, const ArgumentPtr &rhs) { + if (is(rhs)) { + return NegInf().clone(); + } + + if (is(rhs)) { + return Inf().clone(); + } + + return {}; +} + } diff --git a/src/fintamath/expressions/unary/NegExpression.hpp b/src/fintamath/expressions/unary/NegExpression.hpp index 224652766..5d6c723dd 100644 --- a/src/fintamath/expressions/unary/NegExpression.hpp +++ b/src/fintamath/expressions/unary/NegExpression.hpp @@ -23,6 +23,8 @@ class NegExpression : public IUnaryExpressionCRTP { static ArgumentPtr simplifyNegatable(const IFunction &func, const ArgumentPtr &rhs); static ArgumentPtr simplifyNestedNeg(const IFunction &func, const ArgumentPtr &rhs); + + static ArgumentPtr simplifyConst(const IFunction &func, const ArgumentPtr &rhs); }; } \ No newline at end of file diff --git a/src/fintamath/functions/arithmetic/Div.cpp b/src/fintamath/functions/arithmetic/Div.cpp index f7797ca43..1aecc9fce 100644 --- a/src/fintamath/functions/arithmetic/Div.cpp +++ b/src/fintamath/functions/arithmetic/Div.cpp @@ -1,6 +1,8 @@ +#include "fintamath/literals/constants/Inf.hpp" #include "fintamath/numbers/INumber.hpp" #include "fintamath/functions/arithmetic/Div.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/Rational.hpp" @@ -20,6 +22,14 @@ std::unique_ptr Div::call(const ArgumentsRefVector &argsVect) const const auto &lhs = cast(argsVect.front().get()); const auto &rhs = cast(argsVect.back().get()); + if (lhs == Integer(0) && rhs == Integer(0)) { + return Indeterminate().clone(); + } + + if (rhs == Integer(0)) { + return Inf().clone(); + } + if (auto res = multiPow(lhs, rhs)) { return res; } diff --git a/src/fintamath/functions/powers/Pow.cpp b/src/fintamath/functions/powers/Pow.cpp index ec0568dd5..9b1d9fdd9 100644 --- a/src/fintamath/functions/powers/Pow.cpp +++ b/src/fintamath/functions/powers/Pow.cpp @@ -2,6 +2,7 @@ #include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" #include "fintamath/numbers/Integer.hpp" #include "fintamath/numbers/IntegerFunctions.hpp" #include "fintamath/numbers/Rational.hpp" @@ -32,6 +33,10 @@ std::unique_ptr Pow::call(const ArgumentsRefVector &argsVect) const const auto &lhs = cast(argsVect.front().get()); const auto &rhs = cast(argsVect.back().get()); + if (lhs == Integer(0) && rhs == Integer(0)) { + return Indeterminate().clone(); + } + if (rhs < Integer(0)) { return Pow()(*(Rational(1) / lhs), *(-rhs)); } diff --git a/src/fintamath/literals/constants/Indeterminate.cpp b/src/fintamath/literals/constants/Indeterminate.cpp new file mode 100644 index 000000000..ed6f3f93e --- /dev/null +++ b/src/fintamath/literals/constants/Indeterminate.cpp @@ -0,0 +1,11 @@ +#include "fintamath/literals/constants/Indeterminate.hpp" + +#include "fintamath/numbers/RealFunctions.hpp" + +namespace fintamath { + +std::unique_ptr Indeterminate::call() const { + return clone(); +} + +} diff --git a/src/fintamath/literals/constants/Inf.cpp b/src/fintamath/literals/constants/Inf.cpp new file mode 100644 index 000000000..22560b701 --- /dev/null +++ b/src/fintamath/literals/constants/Inf.cpp @@ -0,0 +1,11 @@ +#include "fintamath/literals/constants/Inf.hpp" + +#include "fintamath/numbers/RealFunctions.hpp" + +namespace fintamath { + +std::unique_ptr Inf::call() const { + return clone(); +} + +} diff --git a/src/fintamath/literals/constants/NegInf.cpp b/src/fintamath/literals/constants/NegInf.cpp new file mode 100644 index 000000000..e302a4962 --- /dev/null +++ b/src/fintamath/literals/constants/NegInf.cpp @@ -0,0 +1,11 @@ +#include "fintamath/literals/constants/NegInf.hpp" + +#include "fintamath/numbers/RealFunctions.hpp" + +namespace fintamath { + +std::unique_ptr NegInf::call() const { + return clone(); +} + +} diff --git a/tests/src/expressions/ExpressionTests.cpp b/tests/src/expressions/ExpressionTests.cpp index 957340aee..dd912ed8b 100644 --- a/tests/src/expressions/ExpressionTests.cpp +++ b/tests/src/expressions/ExpressionTests.cpp @@ -81,8 +81,6 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("1100*4.76%").toString(), "1309/25"); EXPECT_EQ(Expression("2.35%%%%").toString(), "47/2000000000"); EXPECT_EQ(Expression("1100*4.76%1100*4.76%").toString(), "1713481/625"); - // TODO: implement infinities - // EXPECT_EQ(Expression("((((((5)/(8)))/(1)))/(((((((9)/(4)))/(0)))/(5))))").toString(), "0"); EXPECT_EQ(Expression("9!").toString(), "362880"); EXPECT_EQ(Expression("-1!").toString(), "-1"); @@ -207,6 +205,7 @@ TEST(ExpressionTests, stringConstructorTest) { EXPECT_EQ(Expression("1deg").toString(), "Pi/180"); EXPECT_EQ(Expression("60deg").toString(), "Pi/3"); EXPECT_EQ(Expression("adeg").toString(), "(Pi a)/180"); + EXPECT_EQ(Expression("((((((5)/(8)))/(1)))/(((((((9)/(4)))/(0)))/(5))))").toString(), "0"); EXPECT_EQ(Expression("a*0").toString(), "0"); EXPECT_EQ(Expression("0*a").toString(), "0"); @@ -669,6 +668,71 @@ TEST(ExpressionTests, stringConstructorTest) { // EXPECT_EQ(Expression("sin(x)^2 + cos(x)^2").toString(), "1"); // TODO: implement // EXPECT_EQ(Expression("tan(x)*cot(x)").toString(), "1"); // TODO: implement // EXPECT_EQ(Expression("tanh(x)*coth(x)").toString(), "1"); // TODO: implement + + EXPECT_EQ(Expression("Inf").toString(), "Inf"); + EXPECT_EQ(Expression("-Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("1/0").toString(), "Inf"); + EXPECT_EQ(Expression("a/0").toString(), "Inf"); + EXPECT_EQ(Expression("1/Inf").toString(), "0"); + EXPECT_EQ(Expression("1/-Inf").toString(), "0"); + EXPECT_EQ(Expression("a/Inf").toString(), "0"); + EXPECT_EQ(Expression("a/-Inf").toString(), "0"); + EXPECT_EQ(Expression("Inf + Inf").toString(), "Inf"); + EXPECT_EQ(Expression("-Inf - Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("10 + Inf").toString(), "Inf"); + EXPECT_EQ(Expression("-10 + Inf").toString(), "Inf"); + EXPECT_EQ(Expression("10 - Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("-10 - Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("10 * Inf").toString(), "Inf"); + EXPECT_EQ(Expression("-10 * Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("-2/3 * Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("Inf * Inf").toString(), "Inf"); + EXPECT_EQ(Expression("Inf * -Inf").toString(), "-Inf"); + EXPECT_EQ(Expression("-Inf * -Inf").toString(), "Inf"); + EXPECT_EQ(Expression("Inf^2").toString(), "Inf"); + EXPECT_EQ(Expression("Inf^(2/3)").toString(), "Inf"); + EXPECT_EQ(Expression("(-Inf)^2").toString(), "Inf"); + EXPECT_EQ(Expression("(-Inf)^3").toString(), "-Inf"); + // EXPECT_EQ(Expression("(-Inf)^(2/3)").toString(), "-Inf"); // TODO! complex numbers + EXPECT_EQ(Expression("0^Inf").toString(), "0"); + EXPECT_EQ(Expression("0^-Inf").toString(), "Inf"); + EXPECT_EQ(Expression("sqrt(2) * Inf").toString(), "Inf sqrt(2)"); // TODO! Inf + EXPECT_EQ(Expression("-sqrt(2) * Inf").toString(), "-Inf sqrt(2)"); // TODO! -Inf + EXPECT_EQ(Expression("sin(Inf)").toString(), "sin(Inf)"); // TODO: [-1, 1] + EXPECT_EQ(Expression("x = Inf").toString(), "x - Inf = 0"); + EXPECT_EQ(Expression("x = -Inf").toString(), "x + Inf = 0"); + + EXPECT_EQ(Expression("0*Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0*-Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Inf - Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0/0").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Inf/Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0/Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Inf/0").toString(), "Indeterminate"); + EXPECT_EQ(Expression("-Inf/-Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0/-Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("-Inf/0").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Inf/-Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("-Inf/Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("-Inf + Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Inf - Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0^0").toString(), "Indeterminate"); + EXPECT_EQ(Expression("1^Inf").toString(), "Indeterminate"); + EXPECT_EQ(Expression("1^-Inf").toString(), "Indeterminate"); + + EXPECT_EQ(Expression("Indeterminate").toString(), "Indeterminate"); + EXPECT_EQ(Expression("-Indeterminate").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Indeterminate + 10").toString(), "Indeterminate"); + EXPECT_EQ(Expression("Indeterminate - 10").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0/Indeterminate").toString(), "Indeterminate"); + EXPECT_EQ(Expression("1/Indeterminate").toString(), "Indeterminate"); + EXPECT_EQ(Expression("sin(Indeterminate)").toString(), "Indeterminate"); + EXPECT_EQ(Expression("sin(0/0)").toString(), "Indeterminate"); + EXPECT_EQ(Expression("1 + 0^0").toString(), "Indeterminate"); + EXPECT_EQ(Expression("1 + sin(asin(0^0)) + x").toString(), "Indeterminate"); + EXPECT_EQ(Expression("1 + (2^2 - 4)^0").toString(), "Indeterminate"); + EXPECT_EQ(Expression("0^((2^2 - 4)^0)").toString(), "Indeterminate"); + EXPECT_EQ(Expression("-((2^2 - 4)^0)").toString(), "Indeterminate"); } TEST(ExpressionTests, stringConstructorLargeTest) { @@ -925,16 +989,14 @@ TEST(ExpressionTests, stringConstructorNegativeTest) { EXPECT_THROW(Expression("(x*2)_((x+2)_x)"), InvalidInputException); EXPECT_THROW(Expression("x^x_1"), InvalidInputException); EXPECT_THROW(Expression("E&a"), InvalidInputException); + EXPECT_THROW(Expression("~Inf"), InvalidInputException); + EXPECT_THROW(Expression("~Indeterminate"), InvalidInputException); EXPECT_THROW(Expression("min()"), InvalidInputException); EXPECT_THROW(Expression("min(True, False)"), InvalidInputException); EXPECT_THROW(Expression("max()"), InvalidInputException); EXPECT_THROW(Expression("max(True, False)"), InvalidInputException); - EXPECT_THROW(Expression("1/0"), UndefinedException); - EXPECT_THROW(Expression("a/0"), UndefinedException); - EXPECT_THROW(Expression("(a/0)/(a/0)"), UndefinedException); - EXPECT_THROW(Expression("0^0"), UndefinedException); EXPECT_THROW(Expression("(-1)!"), UndefinedException); EXPECT_THROW(Expression("(2/3)!"), UndefinedException); EXPECT_THROW(Expression("(-1)!!"), UndefinedException); diff --git a/tests/src/functions/powers/PowFTests.cpp b/tests/src/functions/powers/PowFTests.cpp index 5fbc2cc0b..4424985cc 100644 --- a/tests/src/functions/powers/PowFTests.cpp +++ b/tests/src/functions/powers/PowFTests.cpp @@ -75,7 +75,8 @@ TEST(PowFTests, callTest) { 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(Integer(0), Integer(0)), UndefinedException); + EXPECT_EQ(f(Integer(0), Integer(0))->toString(), "Indeterminate"); + EXPECT_THROW(f(Rational("0"), Rational("-10")), UndefinedException); EXPECT_THROW(f(Rational("-10"), Rational("-1.5")), UndefinedException); diff --git a/tests/src/functions/powers/PowTests.cpp b/tests/src/functions/powers/PowTests.cpp index 440f702dc..0f02042ee 100644 --- a/tests/src/functions/powers/PowTests.cpp +++ b/tests/src/functions/powers/PowTests.cpp @@ -79,7 +79,8 @@ TEST(PowTests, callTest) { 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(Integer(0), Integer(0)), UndefinedException); + EXPECT_EQ(f(Integer(0), Integer(0))->toString(), "Indeterminate"); + EXPECT_THROW(f(Rational("0"), Rational("-10")), UndefinedException); EXPECT_THROW(f(Rational("-10"), Rational("-1.5")), UndefinedException); diff --git a/tests/src/parser/ParserTests.cpp b/tests/src/parser/ParserTests.cpp index 6f39ab0c0..454a5ace0 100644 --- a/tests/src/parser/ParserTests.cpp +++ b/tests/src/parser/ParserTests.cpp @@ -62,6 +62,9 @@ #include "fintamath/literals/constants/E.hpp" #include "fintamath/literals/constants/False.hpp" #include "fintamath/literals/constants/IConstant.hpp" +#include "fintamath/literals/constants/Indeterminate.hpp" +#include "fintamath/literals/constants/Inf.hpp" +#include "fintamath/literals/constants/NegInf.hpp" #include "fintamath/literals/constants/Pi.hpp" #include "fintamath/literals/constants/True.hpp" #include "fintamath/numbers/INumber.hpp" @@ -162,7 +165,6 @@ TEST(ParserTests, parseNumberTest) { TEST(ParserTests, parseLiteralTest) { EXPECT_TRUE(is(ILiteral::parse("E"))); - EXPECT_TRUE(is(ILiteral::parse("Pi"))); EXPECT_TRUE(is(ILiteral::parse("a"))); EXPECT_TRUE(is(ILiteral::parse("z"))); @@ -177,8 +179,11 @@ TEST(ParserTests, parseLiteralTest) { TEST(ParseTests, parseConstantTest) { EXPECT_TRUE(is(IConstant::parse("E"))); EXPECT_TRUE(is(IConstant::parse("Pi"))); - EXPECT_TRUE(is(ILiteral::parse("True"))); - EXPECT_TRUE(is(ILiteral::parse("False"))); + EXPECT_TRUE(is(IConstant::parse("True"))); + EXPECT_TRUE(is(IConstant::parse("False"))); + EXPECT_TRUE(is(IConstant::parse("Inf"))); + EXPECT_TRUE(is(IConstant::parse("-Inf"))); + EXPECT_TRUE(is(IConstant::parse("Indeterminate"))); EXPECT_EQ(IConstant::parse("a"), nullptr); EXPECT_EQ(IConstant::parse("z"), nullptr);