Skip to content

Commit

Permalink
Root simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
fintarin committed Jul 4, 2023
1 parent 6d377e0 commit 1f14fb9
Show file tree
Hide file tree
Showing 20 changed files with 496 additions and 177 deletions.
3 changes: 1 addition & 2 deletions include/fintamath/functions/IFunction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ class IFunction : public IMathObject {

static std::unique_ptr<IMathObject> makeExprChecked(const IFunction &function, const ArgumentsRefVector &args);

// TODO: uncomment
// static std::unique_ptr<IMathObject> makeExpr(const IFunction &function, const ArgumentsRefVector &args);
static std::unique_ptr<IMathObject> makeExpr(const IFunction &function, const ArgumentsPtrVector &args);

static bool isExpression(const ArgumentRef &arg);

Expand Down
10 changes: 10 additions & 0 deletions include/fintamath/functions/powers/Pow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

namespace fintamath {

class Integer;
class Rational;
class Real;

class Pow : public IOperatorCRTP<INumber, Pow, INumber, INumber> {
public:
Pow() : IOperatorCRTP(IOperator::Priority::Exponentiation, false) {
Expand All @@ -20,6 +24,12 @@ class Pow : public IOperatorCRTP<INumber, Pow, INumber, INumber> {

protected:
std::unique_ptr<IMathObject> call(const ArgumentsRefVector &argsVect) const override;

static std::unique_ptr<IMathObject> powSimpl(const Integer &lhs, const Integer &rhs);

static std::unique_ptr<IMathObject> powSimpl(const Rational &lhs, const Rational &rhs);

static std::unique_ptr<IMathObject> powSimpl(const Real &lhs, const Real &rhs);
};

}
35 changes: 35 additions & 0 deletions include/fintamath/functions/powers/Root.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "fintamath/functions/IFunction.hpp"
#include "fintamath/numbers/INumber.hpp"

namespace fintamath {

class Integer;
class Rational;
class Real;

class Root : public IFunctionCRTP<INumber, Root, INumber, INumber> {
public:
Root() = default;

std::string toString() const override {
return "root";
}

protected:
std::unique_ptr<IMathObject> call(const ArgumentsRefVector &argsVect) const override;

private:
static std::unique_ptr<IMathObject> rootSimpl(const Integer &lhs, const Integer &rhs);

static std::unique_ptr<IMathObject> rootSimpl(const Rational &lhs, const Integer &rhs);

static std::unique_ptr<IMathObject> rootSimpl(const Real &lhs, const Integer &rhs);

static std::map<Integer, Integer> roots(const Integer &lhs, const Integer &rhs);

static std::unique_ptr<IMathObject> perfectRoot(const Integer &lhs, const Integer &rhs);
};

}
2 changes: 2 additions & 0 deletions include/fintamath/numbers/IntegerFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Integer factorial(const Integer &rhs);

Integer factorial(const Integer &rhs, size_t order);

std::map<Integer, Integer> factors(Integer rhs, Integer limit = -1);

Integer combinations(const Integer &totalNumber, const Integer &choosedNumber);

Integer multinomialCoefficient(const Integer &totalNumber, const std::vector<Integer> &groupNumbers);
Expand Down
9 changes: 9 additions & 0 deletions src/fintamath/config/ExpressionConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "fintamath/functions/other/Rad.hpp"
#include "fintamath/functions/powers/Exp.hpp"
#include "fintamath/functions/powers/Pow.hpp"
#include "fintamath/functions/powers/Root.hpp"
#include "fintamath/functions/powers/Sqrt.hpp"
#include "fintamath/functions/trigonometry/Acos.hpp"
#include "fintamath/functions/trigonometry/Acot.hpp"
Expand Down Expand Up @@ -308,6 +309,14 @@ struct ExpressionConfig {
return makeExpr(Pow(), args.front(), std::make_shared<Rational>(1, 2));
});

Expression::registerFunctionExpressionMaker<Root>([](const ArgumentsPtrVector &args) {
if (const auto num = cast<INumber>(args.back())) {
return makeExpr(Pow(), args.front(), Integer(1) / (*num));
}

return makeExpr(Pow(), args.front(), makeExpr(Div(), std::make_shared<Integer>(1), args.back()));
});

Expression::registerFunctionExpressionMaker<Sin>([](const ArgumentsPtrVector &args) {
return std::make_shared<TrigonometryExpression>(Sin(), args.front());
});
Expand Down
7 changes: 3 additions & 4 deletions src/fintamath/config/FunctionConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ std::unique_ptr<IMathObject> IFunction::makeExprChecked(const IFunction &functio
return fintamath::makeExprChecked(function, args);
}

// TODO: uncomment
// std::unique_ptr<IMathObject> IFunction::makeExpr(const IFunction &function, const ArgumentsRefVector &args) {
// return fintamath::makeExpr(function, args);
// }
std::unique_ptr<IMathObject> IFunction::makeExpr(const IFunction &function, const ArgumentsPtrVector &args) {
return fintamath::makeExpr(function, args)->clone();
}

bool IFunction::isExpression(const ArgumentRef &arg) {
return is<IExpression>(arg);
Expand Down
2 changes: 2 additions & 0 deletions src/fintamath/config/ParserConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "fintamath/functions/other/Rad.hpp"
#include "fintamath/functions/powers/Exp.hpp"
#include "fintamath/functions/powers/Pow.hpp"
#include "fintamath/functions/powers/Root.hpp"
#include "fintamath/functions/powers/Sqrt.hpp"
#include "fintamath/functions/trigonometry/Acos.hpp"
#include "fintamath/functions/trigonometry/Acot.hpp"
Expand Down Expand Up @@ -172,6 +173,7 @@ struct ParserConfig {
IFunction::registerType<Lg>();
IFunction::registerType<Exp>();
IFunction::registerType<Sqrt>();
IFunction::registerType<Root>();
IFunction::registerType<Sin>();
IFunction::registerType<Cos>();
IFunction::registerType<Tan>();
Expand Down
13 changes: 7 additions & 6 deletions src/fintamath/expressions/binary/PowExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "fintamath/functions/arithmetic/Mul.hpp"
#include "fintamath/functions/arithmetic/Neg.hpp"
#include "fintamath/functions/powers/Pow.hpp"
#include "fintamath/functions/powers/Root.hpp"
#include "fintamath/functions/powers/Sqrt.hpp"
#include "fintamath/numbers/Integer.hpp"
#include "fintamath/numbers/IntegerFunctions.hpp"
Expand All @@ -23,13 +24,12 @@ std::string PowExpression::toString() const {
const Integer &numerator = val->numerator();
const Integer &denominator = val->denominator();

if (denominator == 2) {
if (numerator == 1) {
if (numerator == 1) {
if (denominator == 2) {
return functionToString(Sqrt(), {lhsChild});
}

PowExpression res(std::make_shared<PowExpression>(lhsChild, Rational(1, 2).clone()), numerator.clone());
return res.IBinaryExpression::toString();
return functionToString(Root(), {lhsChild, denominator.clone()});
}
}

Expand All @@ -45,7 +45,9 @@ std::shared_ptr<IFunction> PowExpression::getOutputFunction() const {
}

ArgumentPtr PowExpression::preciseSimplify() const {
if (*rhsChild == Rational(1, 2)) {
static const int64_t maxPreciseRoot = 9;

if (const auto ratRhsChild = cast<Rational>(rhsChild); ratRhsChild && ratRhsChild->denominator() <= maxPreciseRoot) {
auto preciseExpr = cast<PowExpression>(clone());
preciseSimplifyChild(preciseExpr->lhsChild);
return preciseExpr;
Expand Down Expand Up @@ -236,5 +238,4 @@ ArgumentPtr PowExpression::sumSimplify(const ArgumentPtr &lhs, const ArgumentPtr

return {};
}

}
4 changes: 1 addition & 3 deletions src/fintamath/functions/arithmetic/Abs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ std::unique_ptr<IMathObject> Abs::call(const ArgumentsRefVector &argsVect) const
return outMultiAbs;
}();

const auto &rhs = cast<INumber>(argsVect.front().get());

return multiAbs(rhs);
return multiAbs(cast<INumber>(argsVect.front().get()));
}

}
64 changes: 46 additions & 18 deletions src/fintamath/functions/powers/Pow.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "fintamath/functions/powers/Pow.hpp"

#include "fintamath/functions/powers/Root.hpp"
#include "fintamath/functions/powers/Sqrt.hpp"
#include "fintamath/numbers/Integer.hpp"
#include "fintamath/numbers/IntegerFunctions.hpp"
Expand All @@ -14,30 +15,15 @@ std::unique_ptr<IMathObject> Pow::call(const ArgumentsRefVector &argsVect) const
static MultiMethod<std::unique_ptr<IMathObject>(const INumber &, const INumber &)> outMultiPow;

outMultiPow.add<Integer, Integer>([](const Integer &lhs, const Integer &rhs) {
if (rhs < 0) {
return (Rational(1) / pow(lhs, -rhs)).toMinimalObject();
}

return pow(lhs, rhs).toMinimalObject();
return powSimpl(lhs, rhs);
});

outMultiPow.add<Rational, Rational>([](const Rational &lhs, const Rational &rhs) {
const Integer &numerator = rhs.numerator();
const Integer &denominator = rhs.denominator();

if (denominator == 1) {
return pow(lhs, numerator).toMinimalObject();
}

if (denominator == 2) { // TODO: implement nth root
return Pow()(*Sqrt()(lhs), numerator);
}

return pow(convert<Real>(lhs), convert<Real>(rhs)).toMinimalObject();
return powSimpl(lhs, rhs);
});

outMultiPow.add<Real, Real>([](const Real &lhs, const Real &rhs) {
return pow(lhs, rhs).toMinimalObject();
return powSimpl(lhs, rhs);
});

return outMultiPow;
Expand All @@ -46,6 +32,10 @@ std::unique_ptr<IMathObject> Pow::call(const ArgumentsRefVector &argsVect) const
const auto &lhs = cast<INumber>(argsVect.front().get());
const auto &rhs = cast<INumber>(argsVect.back().get());

if (rhs < Integer(0)) {
return Pow()(*(Rational(1) / lhs), *(-rhs));
}

if (auto rhsConv = cast<INumber>(convert(lhs, rhs))) {
return multiPow(lhs, *rhsConv);
}
Expand All @@ -54,4 +44,42 @@ std::unique_ptr<IMathObject> Pow::call(const ArgumentsRefVector &argsVect) const
return multiPow(*lhsConv, rhs);
}

std::unique_ptr<IMathObject> Pow::powSimpl(const Integer &lhs, const Integer &rhs) {
if (rhs < 0) {
return (Rational(1) / pow(lhs, -rhs)).toMinimalObject();
}

return pow(lhs, rhs).toMinimalObject();
}

std::unique_ptr<IMathObject> Pow::powSimpl(const Rational &lhs, const Rational &rhs) {
const Integer &lhsNumerator = lhs.numerator();
const Integer &lhsDenominator = lhs.denominator();

const Integer &rhsNumerator = rhs.numerator();
const Integer &rhsDenominator = rhs.denominator();

if (rhsDenominator == 1) {
if (lhsDenominator == 1) {
return pow(lhsNumerator, rhsNumerator).toMinimalObject();
}

return pow(lhs, rhsNumerator).toMinimalObject();
}

if (lhs < Integer(0)) {
throw UndefinedBinaryOperatorException(Pow().toString(), lhs.toString(), rhs.toString());
}

if (lhsDenominator == 1) {
return Root()(*Pow()(lhsNumerator, rhsNumerator), rhsDenominator);
}

return Root()(*Pow()(lhs, rhsNumerator), rhsDenominator);
}

std::unique_ptr<IMathObject> Pow::powSimpl(const Real &lhs, const Real &rhs) {
return pow(lhs, rhs).toMinimalObject();
}

}
Loading

0 comments on commit 1f14fb9

Please sign in to comment.