Skip to content

Commit

Permalink
Root simplification - first iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
fintarin committed Jun 30, 2023
1 parent 6d377e0 commit a9fbaaa
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 8 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
20 changes: 20 additions & 0 deletions include/fintamath/functions/powers/Root.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

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

namespace fintamath {

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;
};

}
6 changes: 6 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,11 @@ struct ExpressionConfig {
return makeExpr(Pow(), args.front(), std::make_shared<Rational>(1, 2));
});

// TODO! uncomment
// Expression::registerFunctionExpressionMaker<Root>([](const ArgumentsPtrVector &args) {
// 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
8 changes: 6 additions & 2 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 Down Expand Up @@ -29,10 +30,13 @@ std::unique_ptr<IMathObject> Pow::call(const ArgumentsRefVector &argsVect) const
return pow(lhs, numerator).toMinimalObject();
}

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

// TODO! remove
if (denominator == 2) {
return Pow()(*Sqrt()(lhs), numerator);
}

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

Expand Down
82 changes: 82 additions & 0 deletions src/fintamath/functions/powers/Root.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "fintamath/functions/powers/Root.hpp"

#include "fintamath/functions/arithmetic/Add.hpp"
#include "fintamath/numbers/Integer.hpp"
#include "fintamath/numbers/IntegerFunctions.hpp"
#include "fintamath/numbers/Rational.hpp"
#include "fintamath/numbers/Real.hpp"
#include "fintamath/numbers/RealFunctions.hpp"

namespace fintamath {

static std::pair<Integer, Integer> root(Integer lhs, Integer rhs) {
// TODO! this algorithm is too slow
Integer i = 2;
Integer sq = 1;
Integer k = 4;
Integer p = 1;

while (k <= lhs) {
if (lhs % i == 0) {
if (lhs % k == 0) {
lhs /= k;
sq *= i;
}
else {
lhs /= i;
p *= i;
}
}
else {
i += 1;
}
k = i * i;
}

return {sq, lhs * p};
}

std::unique_ptr<IMathObject> Root::call(const ArgumentsRefVector &argsVect) const {
static const auto multiRoot = [] {
static MultiMethod<std::unique_ptr<IMathObject>(const INumber &, const INumber &)> outMultiRoot;

outMultiRoot.add<Integer, Integer>([](const Integer &lhs, const Integer &rhs) {
auto [outsideRoot, insideRoot] = root(lhs, rhs);

if (insideRoot == 1) {
return outsideRoot.clone();
}

return makeExpr(Add(), {outsideRoot.clone(), makeExpr(Root(), {insideRoot.clone(), rhs.clone()})});
});

// outMultiRoot.add<Rational>([](const Rational &rhs) {
// Integer remainder;

// Integer numerator = root(rhs.numerator(), remainder);
// if (remainder != 0) {
// return root(convert<Real>(rhs)).toMinimalObject();
// }

// Integer denominator = root(rhs.denominator(), remainder);
// if (remainder != 0) {
// return root(convert<Real>(rhs)).toMinimalObject();
// }

// return Rational(numerator, denominator).toMinimalObject();
// });

// outMultiRoot.add<Real>([](const Real &rhs) {
// return std::make_unique<Real>(root(rhs));
// });

return outMultiRoot;
}();

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

return multiRoot(lhs, rhs);
}

}
2 changes: 2 additions & 0 deletions src/fintamath/functions/powers/Sqrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
namespace fintamath {

std::unique_ptr<IMathObject> Sqrt::call(const ArgumentsRefVector &argsVect) const {
// TODO! move this logic to Root

static const auto multiSqrt = [] {
static MultiMethod<std::unique_ptr<IMathObject>(const INumber &)> outMultiSqrt;

Expand Down
73 changes: 73 additions & 0 deletions tests/src/functions/powers/RootTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "gtest/gtest.h"

#include "fintamath/exceptions/UndefinedException.hpp"
#include "fintamath/functions/powers/Root.hpp"

#include "fintamath/literals/Variable.hpp"
#include "fintamath/numbers/Rational.hpp"
#include "fintamath/numbers/Real.hpp"

using namespace fintamath;

const Root f;

TEST(RootTests, toStringTest) {
EXPECT_EQ(f.toString(), "root");
}

TEST(RootTests, getFunctionTypeTest) {
EXPECT_EQ(f.getFunctionType(), IFunction::Type::Binary);
}

TEST(RootTests, callTest) {
EXPECT_EQ(f(Integer(100), Integer(2))->toString(), "10");
EXPECT_EQ(f(Integer(25), Integer(2))->toString(), "5");
EXPECT_EQ(f(Integer(100), Integer(2))->toString(), "10");
EXPECT_EQ(f(Integer(144), Integer(2))->toString(), "12");
EXPECT_EQ(f(Integer("10000000000000000000000000000000000000000000000000000"), Integer(2))->toString(),
"100000000000000000000000000");
EXPECT_EQ(f(Integer(10), Integer(2))->toString(),
"3.1622776601683793319988935444327185337195551393252168268575048527925944386392382");
EXPECT_EQ(f(Integer(35), Integer(2))->toString(),
"5.916079783099616042567328291561617048415501230794340322879719669142822459105653");
EXPECT_EQ(f(Integer(4212), Integer(2))->toString(),
"64.899922958351807276145982814468927032523338329214431828788155012089005069274188");
EXPECT_EQ(f(Integer("992188888888"), Integer(2))->toString(),
"996086.7878292533601855411744463733737437739712744225743190752774953323543572221");
// TODO! pass this test
// EXPECT_EQ(f(Integer("68732648273642987365932706179432649827364"), Integer(2))->toString(),
// "262169121510606178721.58566765529332797469887558257026225414531129497927294552571");

// EXPECT_EQ(f(Rational(25))->toString(), "5");
// EXPECT_EQ(f(Rational(25, 169))->toString(), "5/13");
// EXPECT_EQ(f(Rational(144, 49))->toString(), "12/7");
// EXPECT_EQ(f(Rational(144, 49))->toString(), "12/7");
// EXPECT_EQ(f(Rational("1.44"))->toString(), "6/5");
// EXPECT_EQ(f(Rational(1, 10))->toString(),
// "0.31622776601683793319988935444327185337195551393252168268575048527925944386392382");
// EXPECT_EQ(f(Rational(25, 48))->toString(),
// "0.72168783648703220563643597562744681955950218908765859502325290810497209037866668");
// EXPECT_EQ(f(Rational(26, 49))->toString(),
// "0.72843135908468354714688915843182599850911013515708520108356725777513337600888917");
// EXPECT_EQ(f(Rational(45, 67))->toString(),
// "0.81953754706222955297929294102425245239518786681123328404647027909565181499392632");
// EXPECT_EQ(f(Rational("68732648273642987365932706179432649827364.144"))->toString(),
// "262169121510606178721.5856676552933279746991502144551506779910090326304113931067");

// EXPECT_EQ(f(Real(144))->toString(), "12");
// EXPECT_EQ(f(Real(2))->toString(),
// "1.414213562373095048801688724209698078569671875376948073176679737990732478462107");

EXPECT_EQ(f(Variable("a"), Integer(2))->toString(), "root(a, 2)");

EXPECT_THROW(f(Integer(-10)), UndefinedException);
EXPECT_THROW(f(Rational(-9289, 10)), UndefinedException);
EXPECT_THROW(f(Real(-9289)), UndefinedException);

EXPECT_THROW(f(), InvalidInputFunctionException);
EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException);
}

TEST(RootTests, toStringTest1) {
EXPECT_EQ(f.toString(), "root");
}

0 comments on commit a9fbaaa

Please sign in to comment.