diff --git a/.github/workflows/cmake-linux.yml b/.github/workflows/cmake-linux.yml index f8943f94..5e757896 100644 --- a/.github/workflows/cmake-linux.yml +++ b/.github/workflows/cmake-linux.yml @@ -121,7 +121,7 @@ jobs: # Uploads the build, test, and code coverage artifacts. - name: Upload artifacts if: ${{ matrix.build_profiling }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: build-linux-${{ matrix.build_type }}-${{ matrix.c_compiler }} path: | @@ -131,7 +131,7 @@ jobs: overwrite: true - name: Upload PR number - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: pr-number path: ${{ steps.strings.outputs.pr-dir }} diff --git a/cli/main.cpp b/cli/main.cpp index 66a63a4e..aa27fd9d 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -14,6 +14,7 @@ #include #include +#include "Oasis/DifferentiateVisitor.hpp" #include "Oasis/SimplifyVisitor.hpp" template diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 12a40310..1aee40b0 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -4,6 +4,7 @@ set(Oasis_HEADERS Oasis/BinaryExpression.hpp Oasis/Concepts.hpp Oasis/Derivative.hpp + Oasis/DifferentiateVisitor.hpp Oasis/Divide.hpp Oasis/EulerNumber.hpp Oasis/Exponent.hpp diff --git a/include/Oasis/Add.hpp b/include/Oasis/Add.hpp index e3043f7f..3af9f37e 100644 --- a/include/Oasis/Add.hpp +++ b/include/Oasis/Add.hpp @@ -18,7 +18,6 @@ class Add< using BinaryExpression::BinaryExpression; [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; EXPRESSION_TYPE(Add) EXPRESSION_CATEGORY(Associative | Commutative | BinExp) diff --git a/include/Oasis/BinaryExpression.hpp b/include/Oasis/BinaryExpression.hpp index b6ced92a..7049d4ad 100644 --- a/include/Oasis/BinaryExpression.hpp +++ b/include/Oasis/BinaryExpression.hpp @@ -129,10 +129,6 @@ class BinaryExpression : public Expression { return std::make_unique(*static_cast(this)); } - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr override - { - return Generalize()->Differentiate(differentiationVariable); - } [[nodiscard]] auto Equals(const Expression& other) const -> bool final { if (this->GetType() != other.GetType()) { diff --git a/include/Oasis/BoundedBinaryExpression.hpp b/include/Oasis/BoundedBinaryExpression.hpp index 51392e24..4ec06af3 100644 --- a/include/Oasis/BoundedBinaryExpression.hpp +++ b/include/Oasis/BoundedBinaryExpression.hpp @@ -71,10 +71,7 @@ class BoundedBinaryExpression : public BoundedExpression(copy); } - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr override - { - return Generalize()->Differentiate(differentiationVariable); - } + [[nodiscard]] auto Equals(const Expression& other) const -> bool final { if (this->GetType() != other.GetType()) { diff --git a/include/Oasis/Derivative.hpp b/include/Oasis/Derivative.hpp index 1e948580..8f698daa 100644 --- a/include/Oasis/Derivative.hpp +++ b/include/Oasis/Derivative.hpp @@ -18,8 +18,6 @@ class Derivative : public BinaryExpression { Derivative(const Expression& Exp, const Expression& Var); - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr override; - EXPRESSION_TYPE(Derivative) EXPRESSION_CATEGORY(BinExp) }; diff --git a/include/Oasis/DifferentiateVisitor.hpp b/include/Oasis/DifferentiateVisitor.hpp new file mode 100644 index 00000000..fa188446 --- /dev/null +++ b/include/Oasis/DifferentiateVisitor.hpp @@ -0,0 +1,56 @@ +// +// Created by Andrew Nazareth on 9/23/25. +// + +#ifndef DIFFERENTIATEVISITOR_HPP +#define DIFFERENTIATEVISITOR_HPP + +#include +#include + +#include + +#include "Oasis/Visit.hpp" + +namespace Oasis { + +struct DifferentiationOpts { + enum class Multivariate { + SINGLE_VARIABLE, + MULTI_VARIABLE, + } multivariate + = Multivariate::SINGLE_VARIABLE; +}; + +class DifferentiateVisitor final : public TypedVisitor>, std::string>> { +public: + explicit DifferentiateVisitor(const std::unique_ptr& differentiationVariable); + explicit DifferentiateVisitor(const std::unique_ptr& differentiationVariable, const DifferentiationOpts& opts); + + auto TypedVisit(const Real& real) -> RetT override; + auto TypedVisit(const Imaginary& imaginary) -> RetT override; + auto TypedVisit(const Variable& variable) -> RetT override; + auto TypedVisit(const Undefined& undefined) -> RetT override; + auto TypedVisit(const Add& add) -> RetT override; + auto TypedVisit(const Subtract& subtract) -> RetT override; + auto TypedVisit(const Multiply& multiply) -> RetT override; + auto TypedVisit(const Divide& divide) -> RetT override; + auto TypedVisit(const Exponent& exponent) -> RetT override; + auto TypedVisit(const Log& log) -> RetT override; + auto TypedVisit(const Negate& negate) -> RetT override; + auto TypedVisit(const Sine& sine) -> RetT override; + auto TypedVisit(const Derivative& derivative) -> RetT override; + auto TypedVisit(const Integral& integral) -> RetT override; + auto TypedVisit(const Matrix& matrix) -> RetT override; + auto TypedVisit(const EulerNumber&) -> RetT override; + auto TypedVisit(const Pi&) -> RetT override; + auto TypedVisit(const Magnitude& magnitude) -> RetT override; + +private: + std::unique_ptr differentiationVariable; + DifferentiationOpts opts; +}; + +} // Oasis + +#endif // DIFFERENTIATEVISITOR_HPP diff --git a/include/Oasis/Divide.hpp b/include/Oasis/Divide.hpp index 65a9e2bf..312d455e 100644 --- a/include/Oasis/Divide.hpp +++ b/include/Oasis/Divide.hpp @@ -18,8 +18,6 @@ class Divide : public BinaryExpression { Divide(const Expression& dividend, const Expression& divisor); - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; EXPRESSION_TYPE(Divide) diff --git a/include/Oasis/EulerNumber.hpp b/include/Oasis/EulerNumber.hpp index fd0f7503..46388f6a 100644 --- a/include/Oasis/EulerNumber.hpp +++ b/include/Oasis/EulerNumber.hpp @@ -72,8 +72,6 @@ class EulerNumber : public LeafExpression { [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Differentiate(const Expression&) const -> std::unique_ptr final; - EXPRESSION_TYPE(EulerNumber) EXPRESSION_CATEGORY(UnExp) diff --git a/include/Oasis/Exponent.hpp b/include/Oasis/Exponent.hpp index 9ae96bb2..651f7357 100644 --- a/include/Oasis/Exponent.hpp +++ b/include/Oasis/Exponent.hpp @@ -19,8 +19,6 @@ class Exponent : public BinaryExpression { Exponent(const Expression& base, const Expression& power); - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; EXPRESSION_TYPE(Exponent) diff --git a/include/Oasis/Expression.hpp b/include/Oasis/Expression.hpp index 65629559..d79a16be 100644 --- a/include/Oasis/Expression.hpp +++ b/include/Oasis/Expression.hpp @@ -72,7 +72,7 @@ class Expression { * Tries to differentiate this function. * @return the differentiated expression. */ - [[nodiscard]] virtual auto Differentiate(const Expression&) const -> std::unique_ptr; + [[nodiscard]] auto Differentiate(const Expression&) const -> std::unique_ptr; /** * Compares this expression to another expression for equality. diff --git a/include/Oasis/Integral.hpp b/include/Oasis/Integral.hpp index 6f777114..c58969c0 100644 --- a/include/Oasis/Integral.hpp +++ b/include/Oasis/Integral.hpp @@ -20,8 +20,6 @@ class Integral : public BinaryExpression { Integral(const Expression& integrand, const Expression& differential); - [[deprecated]] [[nodiscard]] auto Simplify(const Expression& upper, const Expression& lower) const -> std::unique_ptr /* final */; - EXPRESSION_TYPE(Integral) EXPRESSION_CATEGORY(Associative | Commutative) }; diff --git a/include/Oasis/LeafExpression.hpp b/include/Oasis/LeafExpression.hpp index 21728c15..46a52609 100644 --- a/include/Oasis/LeafExpression.hpp +++ b/include/Oasis/LeafExpression.hpp @@ -35,10 +35,6 @@ class LeafExpression : public Expression { return Generalize()->Integrate(integrationVariable); } - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr override - { - return Generalize()->Differentiate(differentiationVariable); - } auto Substitute(const Expression&, const Expression&) -> std::unique_ptr override { return this->Copy(); diff --git a/include/Oasis/Log.hpp b/include/Oasis/Log.hpp index 93520039..16beb499 100644 --- a/include/Oasis/Log.hpp +++ b/include/Oasis/Log.hpp @@ -20,7 +20,6 @@ class Log : public BinaryExpression { Log(const Expression& base, const Expression& argument); [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; EXPRESSION_TYPE(Log) EXPRESSION_CATEGORY(BinExp) diff --git a/include/Oasis/Magnitude.hpp b/include/Oasis/Magnitude.hpp index 1585b38a..e1fdc758 100644 --- a/include/Oasis/Magnitude.hpp +++ b/include/Oasis/Magnitude.hpp @@ -39,18 +39,6 @@ class Magnitude final : public UnaryExpression { { } - [[nodiscard]] auto Differentiate(const Expression& var) const -> std::unique_ptr override - { - // TODO: Implement - Oasis::SimplifyVisitor simplifyVisitor {}; - - const std::unique_ptr operandDerivative = this->GetOperand().Differentiate(var); - return Magnitude { - *operandDerivative - } - .Generalize(); - } - [[nodiscard]] auto Integrate(const Expression& integrationVar) const -> std::unique_ptr override { // TODO: Implement diff --git a/include/Oasis/Matrix.hpp b/include/Oasis/Matrix.hpp index ff931ea2..f7d840c4 100644 --- a/include/Oasis/Matrix.hpp +++ b/include/Oasis/Matrix.hpp @@ -61,8 +61,6 @@ class Matrix : public LeafExpression { [[nodiscard]] auto Identity() const -> std::unique_ptr; - [[nodiscard]] auto Differentiate(const Expression&) const -> std::unique_ptr final; - auto operator=(const Matrix& other) -> Matrix& = default; private: diff --git a/include/Oasis/Multiply.hpp b/include/Oasis/Multiply.hpp index fc0b1b9d..be03c75e 100644 --- a/include/Oasis/Multiply.hpp +++ b/include/Oasis/Multiply.hpp @@ -16,8 +16,6 @@ class Multiply : public BinaryExpression { public: using BinaryExpression::BinaryExpression; - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; EXPRESSION_TYPE(Multiply) diff --git a/include/Oasis/Negate.hpp b/include/Oasis/Negate.hpp index 06cb17a9..ef7d5ad7 100644 --- a/include/Oasis/Negate.hpp +++ b/include/Oasis/Negate.hpp @@ -24,15 +24,6 @@ class Negate final : public UnaryExpression { { } - [[nodiscard]] auto Differentiate(const Expression& var) const -> std::unique_ptr override - { - const std::unique_ptr operandDerivative = this->GetOperand().Differentiate(var); - return Negate { - *operandDerivative - } - .Generalize(); // TODO: FIX WITH VISITOR - } - EXPRESSION_TYPE(Negate) EXPRESSION_CATEGORY(UnExp) }; diff --git a/include/Oasis/Real.hpp b/include/Oasis/Real.hpp index be8e3e36..459c46b9 100644 --- a/include/Oasis/Real.hpp +++ b/include/Oasis/Real.hpp @@ -32,8 +32,6 @@ class Real : public LeafExpression { [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Differentiate(const Expression&) const -> std::unique_ptr final; - auto operator=(const Real& other) -> Real& = default; private: diff --git a/include/Oasis/Sine.hpp b/include/Oasis/Sine.hpp index 638bdc97..5e32b00f 100644 --- a/include/Oasis/Sine.hpp +++ b/include/Oasis/Sine.hpp @@ -26,8 +26,6 @@ class Sine final : public UnaryExpression { { } - [[nodiscard]] auto Differentiate(const Expression& var) const -> std::unique_ptr override; - [[nodiscard]] auto Integrate(const Expression& var) const -> std::unique_ptr override; EXPRESSION_TYPE(Sine) diff --git a/include/Oasis/Subtract.hpp b/include/Oasis/Subtract.hpp index e2d1c9fd..eb0b8c9a 100644 --- a/include/Oasis/Subtract.hpp +++ b/include/Oasis/Subtract.hpp @@ -19,8 +19,6 @@ class Subtract : public BinaryExpression { Subtract(const Expression& minuend, const Expression& subtrahend); - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; EXPRESSION_TYPE(Subtract) diff --git a/include/Oasis/Variable.hpp b/include/Oasis/Variable.hpp index 4ceda6d3..86194cc9 100644 --- a/include/Oasis/Variable.hpp +++ b/include/Oasis/Variable.hpp @@ -46,8 +46,6 @@ class Variable : public LeafExpression { */ [[nodiscard]] auto GetName() const -> std::string; - [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; - [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; auto Substitute(const Expression& var, const Expression& val) -> std::unique_ptr override; diff --git a/src/Add.cpp b/src/Add.cpp index f357821a..f75a074a 100644 --- a/src/Add.cpp +++ b/src/Add.cpp @@ -62,19 +62,4 @@ auto Add::Integrate(const Expression& integrationVariable) const -> return integral.Copy(); } -auto Add::Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr -{ - if (auto variable = RecursiveCast(differentiationVariable); variable != nullptr) { - auto left = mostSigOp->Differentiate(differentiationVariable); - auto right = leastSigOp->Differentiate(differentiationVariable); - SimplifyVisitor simplifyVisitor; - auto simplified = Add { *left, *right }.Accept(simplifyVisitor); - if (!simplified) { - Add { *left, *right }; - } - return std::move(simplified).value(); - } - return Copy(); -} - } // Oasis \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4378dbe8..d3247428 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ set(Oasis_SOURCES Add.cpp # DefiniteIntegral.cpp Derivative.cpp + DifferentiateVisitor.cpp Divide.cpp EulerNumber.cpp Exponent.cpp diff --git a/src/Derivative.cpp b/src/Derivative.cpp index 346f7e8f..03ba138b 100644 --- a/src/Derivative.cpp +++ b/src/Derivative.cpp @@ -22,9 +22,4 @@ Derivative::Derivative(const Expression& exp, const Expression& var) { } -std::unique_ptr Derivative::Differentiate(const Expression&) const -{ - return mostSigOp->Differentiate(*leastSigOp); -} - } diff --git a/src/DifferentiateVisitor.cpp b/src/DifferentiateVisitor.cpp new file mode 100644 index 00000000..4c94d57d --- /dev/null +++ b/src/DifferentiateVisitor.cpp @@ -0,0 +1,440 @@ +// +// Created by Andrew Nazareth on 9/23/25. +// + +#include + +#include "Oasis/Add.hpp" +#include "Oasis/BinaryExpression.hpp" +#include "Oasis/Derivative.hpp" +#include "Oasis/DifferentiateVisitor.hpp" +#include "Oasis/Divide.hpp" + +#include "Oasis/EulerNumber.hpp" +#include "Oasis/Exponent.hpp" +#include "Oasis/Integral.hpp" +#include "Oasis/Log.hpp" +#include "Oasis/Magnitude.hpp" +#include "Oasis/MatchCast.hpp" +#include "Oasis/Multiply.hpp" +#include "Oasis/Negate.hpp" +#include "Oasis/Pi.hpp" +#include "Oasis/Real.hpp" +#include "Oasis/Sine.hpp" +#include "Oasis/Subtract.hpp" +#include "Oasis/Undefined.hpp" +#include "Oasis/Variable.hpp" + +// I do not know why I defined this. +// namespace { +// constexpr auto EPSILON = std::numeric_limits::epsilon(); +// } + +namespace Oasis { + +DifferentiateVisitor::DifferentiateVisitor(const std::unique_ptr& differentiationVariable) +{ + this->differentiationVariable = differentiationVariable->Copy(); +} +DifferentiateVisitor::DifferentiateVisitor(const std::unique_ptr& differentiationVariable, const DifferentiationOpts& opts) +{ + this->differentiationVariable = differentiationVariable->Copy(); + this->opts = opts; +} + +auto DifferentiateVisitor::TypedVisit(const Real&) -> RetT +{ + return gsl_lite::not_null { std::make_unique(0.0) }; +} + +auto DifferentiateVisitor::TypedVisit(const Imaginary&) -> RetT +{ + return gsl_lite::not_null { std::make_unique(0.0) }; +} + +auto DifferentiateVisitor::TypedVisit(const Variable& var) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + if (variable->GetName() == var.GetName()) { + return gsl_lite::not_null { std::make_unique(1.0) }; + } else if (this->opts.multivariate == DifferentiationOpts::Multivariate::MULTI_VARIABLE) { + return gsl_lite::not_null { std::make_unique>(var, *this->differentiationVariable) }; + } else { + return gsl_lite::not_null { std::make_unique(0.0) }; + } + } + return gsl_lite::not_null { std::make_unique>(var, *this->differentiationVariable) }; +} + +auto DifferentiateVisitor::TypedVisit(const Undefined&) -> RetT +{ + return gsl_lite::not_null { std::make_unique() }; +} + +auto DifferentiateVisitor::TypedVisit(const Add& add) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + auto diffedleft = add.mostSigOp->Accept(*this); + auto diffedright = add.leastSigOp->Accept(*this); + + if (!diffedleft) { + return std::unexpected { diffedleft.error() }; + } + if (!diffedleft) { + return std::unexpected { diffedleft.error() }; + } + + auto left = std::move(diffedleft).value(); + auto right = std::move(diffedright).value(); + + SimplifyVisitor simplifyVisitor {}; + auto simplified = Add { *left, *right }.Accept(simplifyVisitor); + if (!simplified) { + return std::unexpected { simplified.error() }; + } + return std::move(simplified).value(); + } + return gsl_lite::not_null>(Oasis::Derivative { *(add.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Subtract& subtract) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + auto diffedleft = subtract.mostSigOp->Accept(*this); + auto diffedright = subtract.leastSigOp->Accept(*this); + + if (!diffedleft) { + return std::unexpected { diffedleft.error() }; + } + if (!diffedleft) { + return std::unexpected { diffedleft.error() }; + } + + auto left = std::move(diffedleft).value(); + auto right = std::move(diffedright).value(); + + SimplifyVisitor simplifyVisitor {}; + auto simplified = Subtract { *left, *right }.Accept(simplifyVisitor); + if (!simplified) { + return std::unexpected { simplified.error() }; + } + return std::move(simplified).value(); + } + return gsl_lite::not_null>(Oasis::Derivative { *(subtract.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Multiply& multiply) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + auto diffedleft = multiply.mostSigOp->Accept(*this); + auto diffedright = multiply.leastSigOp->Accept(*this); + if (!diffedleft) { + return std::unexpected { diffedleft.error() }; + } + if (!diffedright) { + return std::unexpected { diffedright.error() }; + } + + auto left = std::move(diffedleft).value(); + auto right = std::move(diffedright).value(); + + SimplifyVisitor simplifyVisitor {}; + auto multiplied = Add { + Multiply { *left, *multiply.leastSigOp->Copy() }, + Multiply { *multiply.mostSigOp->Copy(), *right } + }.Accept(simplifyVisitor); + + if (!multiplied) { + return std::unexpected { multiplied.error() }; + } + return std::move(multiplied).value(); + } + return gsl_lite::not_null>(Oasis::Derivative { *(multiply.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Divide& divide) -> RetT +{ + SimplifyVisitor simplifyVisitor {}; + // Single differentiation variable + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + auto simplifiedDiv = divide.Accept(simplifyVisitor).value(); + + // Constant case - differentiation over a divisor + if (auto constant = RecursiveCast>(*simplifiedDiv); constant != nullptr) { + auto exp = constant->GetMostSigOp().Copy(); + auto num = constant->GetLeastSigOp(); + auto differentiate = (*exp).Differentiate(*(this->differentiationVariable)); + if (auto add = RecursiveCast(*differentiate); add != nullptr) { + auto simplifiedAdd = add->Accept(simplifyVisitor).value(); + return std::make_unique>(Divide { *simplifiedAdd, Real { num.GetValue() } })->Accept(simplifyVisitor).value(); + } + } + // In case of simplify turning divide into mult + if (auto constant = RecursiveCast>(*simplifiedDiv); constant != nullptr) { + auto exp = constant->GetMostSigOp().Copy(); + auto num = constant->GetLeastSigOp(); + auto differentiate = (*exp).Differentiate(*(this->differentiationVariable)); + if (auto add = RecursiveCast(*differentiate); add != nullptr) { + auto simplifiedAdd = (add->Accept(simplifyVisitor).value()); + return std::make_unique>(Multiply { *simplifiedAdd, Real { num.GetValue() } })->Accept(simplifyVisitor).value(); + } + } + // Quotient Rule: d/dx (f(x)/g(x)) = (g(x)f'(x)-f(x)g'(x))/(g(x)^2) + if (auto quotient = RecursiveCast>(*simplifiedDiv); quotient != nullptr) { + auto leftexp = quotient->GetMostSigOp().Copy(); + auto rightexp = quotient->GetLeastSigOp().Copy(); + auto leftDiff = leftexp->Differentiate(*(this->differentiationVariable)); + auto rightDiff = rightexp->Differentiate(*(this->differentiationVariable)); + auto mult1 = Multiply(Multiply { *(rightexp->Accept(simplifyVisitor).value()), *(leftDiff->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value()->Accept(simplifyVisitor).value(); + auto mult2 = Multiply(Multiply { *(leftexp->Accept(simplifyVisitor).value()), *(rightDiff->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value()->Accept(simplifyVisitor).value(); + auto numerator = Subtract(Subtract { *mult1, *mult2 }).Accept(simplifyVisitor).value(); + auto denominator = Multiply(Multiply { *(rightexp->Accept(simplifyVisitor).value()), *(rightexp->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value(); + return Divide({ *(numerator->Accept(simplifyVisitor).value()), *(denominator->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value(); + } + } + + return gsl_lite::not_null>(Oasis::Derivative { *(divide.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Exponent& exponent) -> RetT +{ + SimplifyVisitor simplifyVisitor {}; + // Need to check exponential vs polynomial + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + // d/dx (x^n) = n*x^(n-1) + if (auto polynomial = RecursiveCast>(exponent); polynomial != nullptr) { + auto diffedleft = polynomial->GetMostSigOp().Accept(*this); + if (!diffedleft) { + return std::unexpected { diffedleft.error() }; + } + + auto left = std::move(diffedleft).value(); + + auto multiplied = Multiply { + Multiply { + Exponent { + *polynomial->mostSigOp, + Real { polynomial->GetLeastSigOp().GetValue() - 1.0 } }, + *polynomial->leastSigOp, + }, + *left + } + .Accept(simplifyVisitor); + + if (!multiplied) { + return std::unexpected { multiplied.error() }; + } + return std::move(multiplied).value(); + } + // d/dx (a^{u(x)}) = a^{u(x)} * ln(a) * u'(x) + if (auto exponential = RecursiveCast>(exponent); exponential != nullptr) { + auto a = exponential->mostSigOp->Copy(); + auto u = exponential->leastSigOp->Copy(); + auto uprime = u->Accept(*this); + if (!uprime) { + return std::unexpected { uprime.error() }; + } + auto uprime_ = std::move(uprime).value(); + auto lna = Log { EulerNumber {}, *a }; + auto simplified = Multiply { *exponential, + Multiply { + lna, + *uprime_ } }.Accept(simplifyVisitor); + + if (!simplified) { + return std::unexpected { simplified.error() }; + } + return std::move(simplified).value(); + } + if (auto exponential_e = RecursiveCast>(exponent); exponential_e != nullptr) { + auto u = exponential_e->leastSigOp->Copy(); + auto uprime = u->Accept(*this); + + if (!uprime) { + return std::unexpected { uprime.error() }; + } + auto uprime_ = std::move(uprime).value(); + + auto simplified = Multiply { *exponential_e, *uprime_ }.Accept(simplifyVisitor); + if (!simplified) { + return std::unexpected { simplified.error() }; + } + return std::move(simplified).value(); + } + if (auto exponential_var = RecursiveCast>(exponent); (exponential_var != nullptr) && (exponential_var->mostSigOp->GetName() != variable->GetName())) { + auto a = exponential_var->mostSigOp->Copy(); + auto u = exponential_var->leastSigOp->Copy(); + auto uprime = u->Accept(*this); + if (!uprime) { + return std::unexpected { uprime.error() }; + } + auto uprime_ = std::move(uprime).value(); + auto lna = Log { EulerNumber {}, *a }; + auto simplified = Multiply { *exponential_var, + Multiply { + lna, + *uprime_ } }.Accept(simplifyVisitor); + + if (!simplified) { + return std::unexpected { simplified.error() }; + } + return std::move(simplified).value(); + } + + // https://math.stackexchange.com/questions/276041/derivative-of-fxgx#:~:text=dydx=g(x)⋅f(,⋅g′(x). + + auto f = exponent.mostSigOp->Copy(); + auto g = exponent.leastSigOp->Copy(); + + auto df = f->Accept(*this); + if (!df) { + return std::unexpected { df.error() }; + } + auto dg = g->Accept(*this); + if (!dg) { + return std::unexpected { dg.error() }; + } + + auto f_prime = std::move(df).value(); + auto g_prime = std::move(dg).value(); + + auto y = Multiply { + exponent, + Add { + Divide { + Multiply { + *g, + *f_prime }, + *f }, + Multiply { + *g_prime, + Log { EulerNumber {}, *f } } } + }.Accept(simplifyVisitor); + + if (!y) { + return std::unexpected { y.error() }; + } + + return std::move(y).value(); + } + return gsl_lite::not_null>(Oasis::Derivative { *(exponent.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Log& log) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + SimplifyVisitor simplifyVisitor {}; + // d(log_e(6x))/dx = 1/6x * 6 + if (auto lnCase = RecursiveCast(*log.mostSigOp); lnCase != nullptr) { + Divide derivative { Oasis::Real { 1.0 }, *log.leastSigOp }; + Derivative chain { *log.leastSigOp, *(this->differentiationVariable) }; + + Multiply result = Multiply { derivative, *chain.Differentiate(*(this->differentiationVariable)) }; + auto simp = result.Accept(simplifyVisitor); + if (!simp) { + return gsl_lite::not_null> { result.Generalize() }; + } + return std::move(simp).value(); + } else { + if (auto RealCase = RecursiveCast(*log.mostSigOp); RealCase != nullptr) { + Divide derivative { Oasis::Real { 1.0 }, Multiply { *log.leastSigOp, Log { EulerNumber {}, *log.mostSigOp } } }; + auto chain = log.leastSigOp->Accept(*this); + if (!chain) { + return std::unexpected { chain.error() }; + } + Multiply result = Multiply { derivative, **chain }; + auto simp = result.Accept(simplifyVisitor); + if (!simp) { + return gsl_lite::not_null> { result.Generalize() }; + } + return std::move(simp).value(); + } else { + // Use log identity and Quotient rule + Divide result { Subtract { Multiply { Log { EulerNumber {}, *log.mostSigOp }, Derivative { Log { EulerNumber {}, *log.leastSigOp }, *(this->differentiationVariable) } }, + Multiply { Log { EulerNumber {}, *log.leastSigOp }, Derivative { Log { EulerNumber {}, *log.mostSigOp }, *(this->differentiationVariable) } } }, + Exponent { Log { EulerNumber {}, *log.mostSigOp }, Real { 2 } } }; + auto simp = result.Accept(simplifyVisitor); + if (!simp) { + return gsl_lite::not_null> { result.Generalize() }; + } + return std::move(simp).value(); + } + } + } + return gsl_lite::not_null>(Oasis::Derivative { *(log.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Negate& negate) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + const std::unique_ptr operandDerivative = negate.GetOperand().Differentiate(*(this->differentiationVariable)); + return gsl_lite::not_null { Negate { *operandDerivative }.Generalize() }; + } + + return gsl_lite::not_null>(Oasis::Derivative { *(negate.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Sine& sine) -> RetT +{ + // TODO: IMPLEMENT + return std::unexpected { "Not Implemented." }; + return gsl_lite::not_null>(Oasis::Derivative { *(sine.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Derivative& derivative) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + SimplifyVisitor sv {}; + auto diff = derivative.GetMostSigOp().Accept(*this); + if (!diff) { + return gsl_lite::not_null>(Derivative { derivative, *this->differentiationVariable }.Generalize()); + } + auto res = std::move(diff).value(); + auto result = res->Accept(sv); + if (!result) { + return gsl_lite::not_null> { Derivative { *res, *this->differentiationVariable }.Generalize() }; + } + return gsl_lite::not_null> { std::move(result).value() }; + } + return gsl_lite::not_null>(Oasis::Derivative { *(derivative.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Integral& integral) -> RetT +{ + if (auto variable = RecursiveCast(*(this->differentiationVariable)); variable != nullptr) { + auto integral_simp = integral.GetMostSigOp().Integrate(integral.GetLeastSigOp()); + + auto result = integral_simp->Accept(*this); + if (!result) { + return gsl_lite::not_null> { Derivative { *integral_simp, *this->differentiationVariable }.Generalize() }; + } + return gsl_lite::not_null> { std::move(result).value() }; + } + return gsl_lite::not_null>(Oasis::Derivative { *(integral.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Matrix& matrix) -> RetT +{ + // TODO: IMPLEMENT + return std::unexpected { "Not Implemented." }; + return gsl_lite::not_null>(Oasis::Derivative { *(matrix.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const EulerNumber&) -> RetT +{ + return gsl_lite::not_null>(Real { 0.0 }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Pi&) -> RetT +{ + return gsl_lite::not_null>(Real { 0.0 }.Generalize()); +} + +auto DifferentiateVisitor::TypedVisit(const Magnitude& magnitude) -> RetT +{ + // TODO: IMPLEMENT + return std::unexpected { "Not Implemented." }; + return gsl_lite::not_null>(Oasis::Derivative { *(magnitude.Copy()), *(this->differentiationVariable) }.Generalize()); +} + +} // Oasis \ No newline at end of file diff --git a/src/Divide.cpp b/src/Divide.cpp index 35324e4b..7946b380 100644 --- a/src/Divide.cpp +++ b/src/Divide.cpp @@ -40,48 +40,4 @@ auto Divide::Integrate(const Expression& integrationVariable) const return integral.Copy(); } -auto Divide::Differentiate(const Oasis::Expression& differentiationVariable) const -> std::unique_ptr -{ - SimplifyVisitor simplifyVisitor {}; - // Single differentiation variable - if (auto variable = RecursiveCast(differentiationVariable); variable != nullptr) { - auto simplifiedDiv = this->Accept(simplifyVisitor).value(); - - // Constant case - differentiation over a divisor - if (auto constant = RecursiveCast>(*simplifiedDiv); constant != nullptr) { - auto exp = constant->GetMostSigOp().Copy(); - auto num = constant->GetLeastSigOp(); - auto differentiate = (*exp).Differentiate(differentiationVariable); - if (auto add = RecursiveCast(*differentiate); add != nullptr) { - auto simplifiedAdd = add->Accept(simplifyVisitor).value(); - return std::make_unique>(Divide { *simplifiedAdd, Real { num.GetValue() } })->Accept(simplifyVisitor).value(); - } - } - // In case of simplify turning divide into mult - if (auto constant = RecursiveCast>(*simplifiedDiv); constant != nullptr) { - auto exp = constant->GetMostSigOp().Copy(); - auto num = constant->GetLeastSigOp(); - auto differentiate = (*exp).Differentiate(differentiationVariable); - if (auto add = RecursiveCast(*differentiate); add != nullptr) { - auto simplifiedAdd = (add->Accept(simplifyVisitor).value()); - return std::make_unique>(Multiply { *simplifiedAdd, Real { num.GetValue() } })->Accept(simplifyVisitor).value(); - } - } - // Quotient Rule: d/dx (f(x)/g(x)) = (g(x)f'(x)-f(x)g'(x))/(g(x)^2) - if (auto quotient = RecursiveCast>(*simplifiedDiv); quotient != nullptr) { - auto leftexp = quotient->GetMostSigOp().Copy(); - auto rightexp = quotient->GetLeastSigOp().Copy(); - auto leftDiff = leftexp->Differentiate(differentiationVariable); - auto rightDiff = rightexp->Differentiate(differentiationVariable); - auto mult1 = Multiply(Multiply { *(rightexp->Accept(simplifyVisitor).value()), *(leftDiff->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value()->Accept(simplifyVisitor).value(); - auto mult2 = Multiply(Multiply { *(leftexp->Accept(simplifyVisitor).value()), *(rightDiff->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value()->Accept(simplifyVisitor).value(); - auto numerator = Subtract(Subtract { *mult1, *mult2 }).Accept(simplifyVisitor).value(); - auto denominator = Multiply(Multiply { *(rightexp->Accept(simplifyVisitor).value()), *(rightexp->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value(); - return Divide({ *(numerator->Accept(simplifyVisitor).value()), *(denominator->Accept(simplifyVisitor).value()) }).Accept(simplifyVisitor).value(); - } - } - - return Copy(); -} - } // Oasis \ No newline at end of file diff --git a/src/EulerNumber.cpp b/src/EulerNumber.cpp index 95d651b1..08483d03 100644 --- a/src/EulerNumber.cpp +++ b/src/EulerNumber.cpp @@ -24,11 +24,6 @@ auto EulerNumber::GetValue() -> double return std::numbers::e; } -auto EulerNumber::Differentiate(const Expression&) const -> std::unique_ptr -{ - return std::make_unique(0); -} - auto EulerNumber::Integrate(const Expression& integrationVariable) const -> std::unique_ptr { SimplifyVisitor simplifyVisitor {}; diff --git a/src/Exponent.cpp b/src/Exponent.cpp index 65e624d2..8940dd93 100644 --- a/src/Exponent.cpp +++ b/src/Exponent.cpp @@ -70,78 +70,4 @@ auto Exponent::Integrate(const Expression& integrationVariable) cons return integral.Copy(); } -auto Exponent::Differentiate( - const Expression& differentiationVariable) const -> std::unique_ptr -{ - // variable diff - SimplifyVisitor simplifyVisitor {}; - if (auto variable = RecursiveCast(differentiationVariable); variable != nullptr) { - auto simplified = this->Accept(simplifyVisitor); - if (!simplified) { - return this->Generalize(); - } - auto simplifiedExponent = std::move(simplified).value(); - - std::unique_ptr diff; - // Variable with a constant power - if (auto realExponent = RecursiveCast>(*simplifiedExponent); realExponent != nullptr) { - const Variable& expBase = realExponent->GetMostSigOp(); - const Real& expPow = realExponent->GetLeastSigOp(); - - if (variable->GetName() == expBase.GetName()) { - return Multiply { - Real { expPow.GetValue() }, - Exponent { - Variable { variable->GetName() }, - Real { expPow.GetValue() - 1 } } - } - .Accept(simplifyVisitor) - .value(); - } - } - - if (auto natBase = RecursiveCast>(*simplifiedExponent); natBase != nullptr) { - Multiply derivative { Derivative { natBase->GetLeastSigOp(), differentiationVariable }, *simplifiedExponent }; - return derivative.Accept(simplifyVisitor).value(); - } - - if (auto realBase = RecursiveCast>(*simplifiedExponent); realBase != nullptr) { - Multiply derivative { - Multiply { Derivative { realBase->GetLeastSigOp(), differentiationVariable }, *simplifiedExponent }, - Log { EulerNumber {}, realBase->GetMostSigOp() } - }; - return derivative.Accept(simplifyVisitor).value(); - } - - if (auto varBase = RecursiveCast>(*simplifiedExponent); varBase != nullptr) { - const Variable& expBase = varBase->GetMostSigOp(); - if (expBase.GetName() != variable->GetName()) { - Multiply derivative { - Multiply { Derivative { varBase->GetLeastSigOp(), differentiationVariable }, *simplifiedExponent }, - Log { EulerNumber {}, varBase->GetMostSigOp() } - }; - return derivative.Accept(simplifyVisitor).value(); - } - } - - if (auto generalCase = RecursiveCast>(*simplifiedExponent); generalCase != nullptr) { - Multiply derivative { - Multiply { - *simplifiedExponent, - Add { - Divide { - Multiply { - generalCase->GetLeastSigOp(), - Derivative { generalCase->GetMostSigOp(), differentiationVariable } }, - generalCase->GetMostSigOp() }, - Multiply { - Derivative { generalCase->GetLeastSigOp(), differentiationVariable }, - Log { EulerNumber {}, generalCase->GetMostSigOp() } } } } - }; - return derivative.Accept(simplifyVisitor).value(); - } - } - - return Derivative { *this, differentiationVariable }.Copy(); -} } // Oasis \ No newline at end of file diff --git a/src/Expression.cpp b/src/Expression.cpp index e32a727c..e5fb0486 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -1,6 +1,8 @@ #include #include +#include +#include #include #include #include @@ -221,9 +223,14 @@ auto Expression::GetCategory() const -> uint32_t return 0; } -auto Expression::Differentiate(const Expression&) const -> std::unique_ptr +auto Expression::Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr { - return Copy(); + DifferentiateVisitor dv { differentiationVariable.Copy() }; + auto diffed = Accept(dv); + if (!diffed) { + return Derivative { *(this->Copy()), differentiationVariable }.Generalize(); + } + return std::move(diffed).value(); } auto Expression::GetType() const -> ExpressionType diff --git a/src/Integral.cpp b/src/Integral.cpp index ac901ad8..b7a8b198 100644 --- a/src/Integral.cpp +++ b/src/Integral.cpp @@ -15,122 +15,121 @@ Integral::Integral(const Expression& integrand, const Expression& di { } -auto Integral::Simplify(const Expression& upper, const Expression& lower) const -> std::unique_ptr -{ - // Returns simplified Integral - SimplifyVisitor simplifyVisitor {}; - - std::unique_ptr simplifiedIntegrand = mostSigOp ? mostSigOp->Accept(simplifyVisitor).value() : std::unique_ptr { nullptr }; - std::unique_ptr simplifiedDifferential = leastSigOp ? leastSigOp->Accept(simplifyVisitor).value() : std::unique_ptr { nullptr }; - - return simplifiedIntegrand->IntegrateWithBounds(*simplifiedDifferential, upper, lower); - /* - Integral simplifiedIntegrate { *simplifiedIntegrand, *simplifiedDifferential }; +// auto Integral::Simplify(const Expression& upper, const Expression& lower) const -> std::unique_ptr +// { +// // Returns simplified Integral +// SimplifyVisitor simplifyVisitor {}; +// +// std::unique_ptr simplifiedIntegrand = mostSigOp ? mostSigOp->Accept(simplifyVisitor).value() : std::unique_ptr { nullptr }; +// std::unique_ptr simplifiedDifferential = leastSigOp ? leastSigOp->Accept(simplifyVisitor).value() : std::unique_ptr { nullptr }; +// +// return simplifiedIntegrand->IntegrateWithBounds(*simplifiedDifferential, upper, lower); +/* + Integral simplifiedIntegrate { *simplifiedIntegrand, *simplifiedDifferential }; - // Bounded Integration Rules + // Bounded Integration Rules - // Constant Rule - if (auto constCase = RecursiveCast>(simplifiedIntegrate); constCase != nullptr) { - const Real& constant = constCase->GetMostSigOp(); + // Constant Rule + if (auto constCase = RecursiveCast>(simplifiedIntegrate); constCase != nullptr) { + const Real& constant = constCase->GetMostSigOp(); - auto upper_bound = RecursiveCast(upper); - auto lower_bound = RecursiveCast(lower); + auto upper_bound = RecursiveCast(upper); + auto lower_bound = RecursiveCast(lower); - if (upper_bound != nullptr && lower_bound != nullptr) { - return std::make_unique((constant.GetValue() * upper_bound->GetValue()) - (constant.GetValue() * lower_bound->GetValue())); - } else if (upper_bound != nullptr && lower_bound == nullptr) { - return std::make_unique>(Real { constant.GetValue() * upper_bound->GetValue() }, *Multiply { constant, lower }.Simplify()); - } else if (upper_bound == nullptr && lower_bound != nullptr) { - return std::make_unique>(*Multiply { constant, upper }.Simplify(), Real { constant.GetValue() * lower_bound->GetValue() }); - } - return std::make_unique>(*Multiply { constant, upper }.Simplify(), *Multiply { constant, lower }.Simplify()); + if (upper_bound != nullptr && lower_bound != nullptr) { + return std::make_unique((constant.GetValue() * upper_bound->GetValue()) - (constant.GetValue() * lower_bound->GetValue())); + } else if (upper_bound != nullptr && lower_bound == nullptr) { + return std::make_unique>(Real { constant.GetValue() * upper_bound->GetValue() }, *Multiply { constant, lower }.Simplify()); + } else if (upper_bound == nullptr && lower_bound != nullptr) { + return std::make_unique>(*Multiply { constant, upper }.Simplify(), Real { constant.GetValue() * lower_bound->GetValue() }); } - - if (auto constCase = RecursiveCast, Variable>>(simplifiedIntegrate); constCase != nullptr) { - Oasis::Divide constant { constCase->GetMostSigOp() }; - auto constReal = RecursiveCast(*constant.Simplify()); - - auto upper_bound = RecursiveCast(upper); - auto lower_bound = RecursiveCast(lower); - - if (upper_bound != nullptr && lower_bound != nullptr) { - return std::make_unique((Real { *constReal }.GetValue() * upper_bound->GetValue()) - (Real { *constReal }.GetValue() * lower_bound->GetValue())); - } else if (upper_bound != nullptr && lower_bound == nullptr) { - return std::make_unique>(Real { Real { *constReal }.GetValue() * upper_bound->GetValue() }, *Multiply { *(constReal), lower }.Simplify()); - } else if (upper_bound == nullptr && lower_bound != nullptr) { - return std::make_unique>(*Multiply { *(constReal), upper }.Simplify(), Real { Real { *constReal }.GetValue() * lower_bound->GetValue() }); - } - return std::make_unique>(*Multiply { *(constReal), upper }.Simplify(), *Multiply { *(constReal), lower }.Simplify()); + return std::make_unique>(*Multiply { constant, upper }.Simplify(), *Multiply { constant, lower }.Simplify()); + } + + if (auto constCase = RecursiveCast, Variable>>(simplifiedIntegrate); constCase != nullptr) { + Oasis::Divide constant { constCase->GetMostSigOp() }; + auto constReal = RecursiveCast(*constant.Simplify()); + + auto upper_bound = RecursiveCast(upper); + auto lower_bound = RecursiveCast(lower); + + if (upper_bound != nullptr && lower_bound != nullptr) { + return std::make_unique((Real { *constReal }.GetValue() * upper_bound->GetValue()) - (Real { *constReal }.GetValue() * lower_bound->GetValue())); + } else if (upper_bound != nullptr && lower_bound == nullptr) { + return std::make_unique>(Real { Real { *constReal }.GetValue() * upper_bound->GetValue() }, *Multiply { *(constReal), lower }.Simplify()); + } else if (upper_bound == nullptr && lower_bound != nullptr) { + return std::make_unique>(*Multiply { *(constReal), upper }.Simplify(), Real { Real { *constReal }.GetValue() * lower_bound->GetValue() }); } + return std::make_unique>(*Multiply { *(constReal), upper }.Simplify(), *Multiply { *(constReal), lower }.Simplify()); + } - // Power Rule - if (auto powerCase = RecursiveCast, Variable>>(simplifiedIntegrate); powerCase != nullptr) { - const Variable& differential = powerCase->GetLeastSigOp(); - Oasis::Exponent exponent { powerCase->GetMostSigOp() }; - auto integral = RecursiveCast, Real>, Variable>>(*exponent.Integrate(differential)); + // Power Rule + if (auto powerCase = RecursiveCast, Variable>>(simplifiedIntegrate); powerCase != nullptr) { + const Variable& differential = powerCase->GetLeastSigOp(); + Oasis::Exponent exponent { powerCase->GetMostSigOp() }; + auto integral = RecursiveCast, Real>, Variable>>(*exponent.Integrate(differential)); - auto upper_bound = RecursiveCast(upper); - auto lower_bound = RecursiveCast(lower); + auto upper_bound = RecursiveCast(upper); + auto lower_bound = RecursiveCast(lower); - if (upper_bound != nullptr && lower_bound != nullptr) { + if (upper_bound != nullptr && lower_bound != nullptr) { - // const Real& divisor = integral->GetMostSigOp().GetLeastSigOp(); - // const Real& power = integral->GetMostSigOp().GetMostSigOp().GetLeastSigOp(); - // const IExpression auto& left = Exponent{ Real{upper_bound->GetValue()}, power }; - // const IExpression auto& right = *Exponent{ Real{lower_bound->GetValue()}, power }.Simplify(); + // const Real& divisor = integral->GetMostSigOp().GetLeastSigOp(); + // const Real& power = integral->GetMostSigOp().GetMostSigOp().GetLeastSigOp(); + // const IExpression auto& left = Exponent{ Real{upper_bound->GetValue()}, power }; + // const IExpression auto& right = *Exponent{ Real{lower_bound->GetValue()}, power }.Simplify(); - // return make_unique( *Subtract{ *Divide{ left, divisor }.Simplify(), *Divide{ right, divisor }.Simplify() }.Simplify() ); - } else if (upper_bound != nullptr && lower_bound == nullptr) { + // return make_unique( *Subtract{ *Divide{ left, divisor }.Simplify(), *Divide{ right, divisor }.Simplify() }.Simplify() ); + } else if (upper_bound != nullptr && lower_bound == nullptr) { - } else if (upper_bound == nullptr && lower_bound != nullptr) { - } - // return + } else if (upper_bound == nullptr && lower_bound != nullptr) { } - // - // // Constant + Power Rule - // if (auto powerCase = RecursiveCast>, Variable>>(simplifiedIntegrate); powerCase != nullptr) { - // const Variable& differential = powerCase->GetLeastSigOp(); - // Oasis::Exponent exponent{powerCase->GetMostSigOp().GetLeastSigOp()}; - // auto integration = exponent.Integrate(differential); - // - // return std::make_unique>(powerCase->GetMostSigOp().GetMostSigOp(), (*integration)); - // } - // - // if (auto powerCase = RecursiveCast, Expression>, Variable>>(simplifiedIntegrate); powerCase != nullptr) { - // const Variable& differential = powerCase->GetLeastSigOp(); - // Oasis::Exponent exponent{powerCase->GetMostSigOp().GetMostSigOp()}; - // auto integration = exponent.Integrate(differential); - // - // return std::make_unique>(powerCase->GetMostSigOp().GetLeastSigOp(), (*integration)); - // } - - // U Substitution Rule - // Needs Differentiation Implementation for U-Sub - - // Exponential Rule - a^x - // Needs Euler's Number for Exponential Functions - - // Natural Log Rule - // Needs Euler's Number for Exponential Functions - - // Euler's Number - // Needs Euler's Number for Exponential Functions - - // Trigonometric Rules - // Needs Trig for Exponential Functions - - // Powers of Sin and Cos - // Needs Trig for Exponential Functions - - // Integration by Parts - // Needs Trig and Euler's Number - - // Partial Fraction Decomposition - // Work in Progress - - // return simplifiedIntegrate.Copy(); - return Copy(); - */ -} - + // return + } + // + // // Constant + Power Rule + // if (auto powerCase = RecursiveCast>, Variable>>(simplifiedIntegrate); powerCase != nullptr) { + // const Variable& differential = powerCase->GetLeastSigOp(); + // Oasis::Exponent exponent{powerCase->GetMostSigOp().GetLeastSigOp()}; + // auto integration = exponent.Integrate(differential); + // + // return std::make_unique>(powerCase->GetMostSigOp().GetMostSigOp(), (*integration)); + // } + // + // if (auto powerCase = RecursiveCast, Expression>, Variable>>(simplifiedIntegrate); powerCase != nullptr) { + // const Variable& differential = powerCase->GetLeastSigOp(); + // Oasis::Exponent exponent{powerCase->GetMostSigOp().GetMostSigOp()}; + // auto integration = exponent.Integrate(differential); + // + // return std::make_unique>(powerCase->GetMostSigOp().GetLeastSigOp(), (*integration)); + // } + + // U Substitution Rule + // Needs Differentiation Implementation for U-Sub + + // Exponential Rule - a^x + // Needs Euler's Number for Exponential Functions + + // Natural Log Rule + // Needs Euler's Number for Exponential Functions + + // Euler's Number + // Needs Euler's Number for Exponential Functions + + // Trigonometric Rules + // Needs Trig for Exponential Functions + + // Powers of Sin and Cos + // Needs Trig for Exponential Functions + + // Integration by Parts + // Needs Trig and Euler's Number + + // Partial Fraction Decomposition + // Work in Progress + + // return simplifiedIntegrate.Copy(); + return Copy(); + */ +// } } // Oasis diff --git a/src/Log.cpp b/src/Log.cpp index 3698cda1..33cd7318 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -112,42 +112,4 @@ auto Log::Integrate(const Oasis::Expression& integrationVariable) co return Integral { *this, integrationVariable }.Generalize(); } -auto Log::Differentiate(const Oasis::Expression& differentiationVariable) const -> std::unique_ptr -{ - SimplifyVisitor simplifyVisitor {}; - // d(log_e(6x))/dx = 1/6x * 6 - if (auto lnCase = RecursiveCast(*mostSigOp); lnCase != nullptr) { - Divide derivative { Oasis::Real { 1.0 }, *leastSigOp }; - Derivative chain { *leastSigOp, differentiationVariable }; - - Multiply result = Multiply { derivative, *chain.Differentiate(differentiationVariable) }; - auto simp = result.Accept(simplifyVisitor); - if (!simp) { - return result.Generalize(); - } - return std::move(simp).value(); - } else { - if (auto RealCase = RecursiveCast(*mostSigOp); RealCase != nullptr) { - Divide derivative { Oasis::Real { 1.0 }, Multiply { *leastSigOp, Log { EulerNumber {}, *mostSigOp } } }; - Derivative chain { *leastSigOp, differentiationVariable }; - Multiply result = Multiply { derivative, *chain.Differentiate(differentiationVariable) }; - auto simp = result.Accept(simplifyVisitor); - if (!simp) { - return result.Generalize(); - } - return std::move(simp).value(); - } else { - // Use log identity and Quotient rule - Divide result { Subtract { Multiply { Log { EulerNumber {}, *mostSigOp }, Derivative { Log { EulerNumber {}, *leastSigOp }, differentiationVariable } }, - Multiply { Log { EulerNumber {}, *leastSigOp }, Derivative { Log { EulerNumber {}, *mostSigOp }, differentiationVariable } } }, - Exponent { Log { EulerNumber {}, *mostSigOp }, Real { 2 } } }; - auto simp = result.Accept(simplifyVisitor); - if (!simp) { - return result.Generalize(); - } - return std::move(simp).value(); - } - } -} - } // Oasis diff --git a/src/Matrix.cpp b/src/Matrix.cpp index 0912f66f..f1b4d825 100644 --- a/src/Matrix.cpp +++ b/src/Matrix.cpp @@ -31,12 +31,6 @@ Matrix::Matrix(size_t numRows, size_t numCols, std::vector& vals) } } -// TO DO: Fix? -auto Matrix::Differentiate(const Expression&) const -> std::unique_ptr -{ - return std::make_unique(0); -} - auto Matrix::Equals(const Expression& other) const -> bool { return other.Is() && matrix.rows() == dynamic_cast(other).matrix.rows() diff --git a/src/Multiply.cpp b/src/Multiply.cpp index dd522474..ba4dd743 100644 --- a/src/Multiply.cpp +++ b/src/Multiply.cpp @@ -146,47 +146,4 @@ auto Multiply::Integrate(const Expression& integrationVariable) cons return integral.Copy(); } -auto Multiply::Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr -{ - SimplifyVisitor simplifyVisitor {}; - // Single integration variable - if (auto variable = RecursiveCast(differentiationVariable); variable != nullptr) { - auto s = this->Accept(simplifyVisitor); - if (!s) { - return this->Generalize(); - } - auto simplifiedMult = std::move(s).value(); - - // Constant case - Constant number multiplied by differentiate - if (auto constant = RecursiveCast>(*simplifiedMult); constant != nullptr) { - auto exp = constant->GetLeastSigOp().Copy(); - auto num = constant->GetMostSigOp(); - auto differentiate = (*exp).Differentiate(differentiationVariable); - if (auto add = RecursiveCast(*differentiate); add != nullptr) { - return std::make_unique>(Multiply { Real { num.GetValue() }, *(add->Accept(simplifyVisitor).value()) })->Accept(simplifyVisitor).value(); - } - - } - // Product rule: d/dx (f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x) - else if (auto product = RecursiveCast>(*simplifiedMult); product != nullptr) { - auto left = product->GetMostSigOp().Copy(); - auto right = product->GetLeastSigOp().Copy(); - auto ld = left->Differentiate(differentiationVariable); - auto rd = right->Differentiate(differentiationVariable); - auto add = RecursiveCast(*ld); - auto add2 = RecursiveCast(*rd); - if ((add != nullptr && add2 != nullptr)) { - return std::make_unique, - Multiply>>(Add, Multiply> { Multiply { *add, - *right }, - Multiply { *add2, *left } }) - ->Accept(simplifyVisitor) - .value(); - } - } - } - - return Copy(); -} - } // Oasis \ No newline at end of file diff --git a/src/Real.cpp b/src/Real.cpp index 7fecdd46..f9f00bd1 100644 --- a/src/Real.cpp +++ b/src/Real.cpp @@ -18,11 +18,6 @@ Real::Real(double value) { } -auto Real::Differentiate(const Expression&) const -> std::unique_ptr -{ - return std::make_unique(0); -} - auto Real::Equals(const Expression& other) const -> bool { return other.Is() && value == dynamic_cast(other).value; diff --git a/src/Sine.cpp b/src/Sine.cpp index a849d599..e4da3b23 100644 --- a/src/Sine.cpp +++ b/src/Sine.cpp @@ -7,10 +7,6 @@ #include "Oasis/UnaryExpression.hpp" namespace Oasis { -auto Sine::Differentiate(const Expression&) const -> std::unique_ptr -{ - return nullptr; -} auto Sine::Integrate(const Expression&) const -> std::unique_ptr { diff --git a/src/Subtract.cpp b/src/Subtract.cpp index ee58cc6e..eddb4dd9 100644 --- a/src/Subtract.cpp +++ b/src/Subtract.cpp @@ -19,49 +19,6 @@ Subtract::Subtract(const Expression& minuend, const Expression& subt { } -auto Subtract::Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr -{ - SimplifyVisitor simplifyVisitor {}; - // Single diff variable - if (auto variable = RecursiveCast(differentiationVariable); variable != nullptr) { - auto s = this->Accept(simplifyVisitor); - if (!s) { - return this->Generalize(); - } - auto simplifiedSub = std::move(s).value(); - - // Make sure we're still subtracting - if (auto adder = RecursiveCast>(*simplifiedSub); adder != nullptr) { - auto rightRef = adder->GetLeastSigOp().Copy(); - auto rightDiff = rightRef->Differentiate(differentiationVariable); - - auto specializedRight = RecursiveCast(*rightDiff); - - auto leftRef = adder->GetMostSigOp().Copy(); - auto leftDiff = leftRef->Differentiate(differentiationVariable); - - auto specializedLeft = RecursiveCast(*leftDiff); - - if (specializedLeft == nullptr || specializedRight == nullptr) { - return Copy(); - } - - auto us = std::make_unique>(Subtract { *(specializedLeft->Copy()), *(specializedRight->Copy()) }); - auto s1 = us->Accept(simplifyVisitor); - if (!s1) { - return us; - } - return std::move(s1).value(); - - } - // If not, use other differentiation technique - else { - return simplifiedSub->Differentiate(differentiationVariable); - } - } - return Copy(); -} - auto Subtract::Integrate(const Expression& integrationVariable) const -> std::unique_ptr { SimplifyVisitor simplifyVisitor {}; diff --git a/src/Variable.cpp b/src/Variable.cpp index 9e0772ea..ca3db9f1 100644 --- a/src/Variable.cpp +++ b/src/Variable.cpp @@ -70,26 +70,4 @@ auto Variable::Substitute(const Expression& var, const Expression& val) -> std:: return Copy(); } -auto Variable::Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr -{ - SimplifyVisitor simplifyVisitor {}; - - if (auto variable = RecursiveCast(differentiationVariable); variable != nullptr) { - - // Power rule - if (name == (*variable).GetName()) { - return std::make_unique(Real { 1.0f }) - ->Accept(simplifyVisitor) - .value(); - } - - // Different variable, treat as constant - return std::make_unique(Real { 0 }) - ->Accept(simplifyVisitor) - .value(); - } - - return Copy(); -} - } // Oasis \ No newline at end of file diff --git a/tests/AddTests.cpp b/tests/AddTests.cpp index 64898a6e..3e2d296a 100644 --- a/tests/AddTests.cpp +++ b/tests/AddTests.cpp @@ -8,14 +8,16 @@ #include "Oasis/Add.hpp" #include "Oasis/Exponent.hpp" #include "Oasis/Imaginary.hpp" +#include "Oasis/Log.hpp" #include "Oasis/Multiply.hpp" #include "Oasis/Real.hpp" #include "Oasis/RecursiveCast.hpp" -#include "Oasis/Variable.hpp" -#include "Oasis/Log.hpp" #include "Oasis/SimplifyVisitor.hpp" +#include "Oasis/Variable.hpp" -namespace { Oasis::SimplifyVisitor simplifyVisitor{}; } +namespace { +Oasis::SimplifyVisitor simplifyVisitor {}; +} TEST_CASE("Addition", "[Add]") { @@ -40,18 +42,19 @@ TEST_CASE("Symbolic Addition", "[Add][Symbolic]") Oasis::Add add { Oasis::Multiply { Oasis::Real { 1.0 }, - Oasis::Variable { "x"} }, + Oasis::Variable { "x" } }, Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Variable { "x" } } - }; + Oasis::Real { 2.0 }, + Oasis::Variable { "x" } } + }; auto simplified = add.Accept(simplifyVisitor).value(); REQUIRE(simplified->Is()); REQUIRE(Oasis::Multiply { Oasis::Real { 3.0 }, - Oasis::Variable { "x" } }.Equals(*simplified)); + Oasis::Variable { "x" } } + .Equals(*simplified)); } TEST_CASE("Symbolic Addition, variable case", "[Add][Symbolic]") @@ -61,9 +64,9 @@ TEST_CASE("Symbolic Addition, variable case", "[Add][Symbolic]") Oasis::Real { 1.0 }, Oasis::Variable { "x" } }, Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Variable { "x" } } - }; + Oasis::Real { 2.0 }, + Oasis::Variable { "x" } } + }; auto simplified = add.Accept(simplifyVisitor).value(); @@ -71,7 +74,8 @@ TEST_CASE("Symbolic Addition, variable case", "[Add][Symbolic]") Oasis::Real { 1.0 }, Oasis::Multiply { Oasis::Real { 3.0 }, - Oasis::Variable { "x" } }}.Equals(*simplified)); + Oasis::Variable { "x" } } } + .Equals(*simplified)); } TEST_CASE("Generalized Addition", "[Add][Generalized]") @@ -119,8 +123,7 @@ TEST_CASE("Specialization", "[Specialization]") REQUIRE(Oasis::RecursiveCast>( Oasis::Add { Oasis::Real {}, - Oasis::Real {} } - )); + Oasis::Real {} })); } TEST_CASE("Imaginary Addition", "[Imaginary][Add]") @@ -157,7 +160,7 @@ TEST_CASE("Addition Associativity", "[Add][Associative]") Oasis::Multiply { Oasis::Real { 6.0 }, Oasis::Variable { "x" } } } - .Equals(*simplified1)); + .Equals(*simplified1)); } TEST_CASE("Add Associativity with wider tree", "[Add][Associativity]") @@ -196,21 +199,19 @@ TEST_CASE("Add Associativity with wider tree", "[Add][Associativity]") Oasis::Multiply { Oasis::Real { 5.0 }, Oasis::Variable { "x" } } } - .Equals(*simplified2)); + .Equals(*simplified2)); } - TEST_CASE("Add Operator Overload", "[Add][Operator Overload]") { const std::unique_ptr a = std::make_unique(1.0); const std::unique_ptr b = std::make_unique(2.0); - const auto sum = a+b; + const auto sum = a + b; auto realSum = Oasis::RecursiveCast(*sum); REQUIRE(realSum != nullptr); REQUIRE(realSum->GetValue() == 3.0); - } TEST_CASE("Variadic Add Constructor", "[Add]") @@ -236,8 +237,8 @@ TEST_CASE("Complex Addition Associativity", "[Add][Associativity][Simplification const Oasis::Add<> add { Oasis::Real { 1.0 }, Oasis::Multiply { - Oasis::Add { - Oasis::Variable {"x"}, + Oasis::Add { + Oasis::Variable { "x" }, Oasis::Real { 1.0 } }, Oasis::Log { Oasis::Variable { "e" }, @@ -248,8 +249,8 @@ TEST_CASE("Complex Addition Associativity", "[Add][Associativity][Simplification const Oasis::Add<> expected { Oasis::Real { 2.0 }, Oasis::Multiply { - Oasis::Add { - Oasis::Variable {"x"}, + Oasis::Add { + Oasis::Variable { "x" }, Oasis::Real { 1.0 } }, Oasis::Log { Oasis::Variable { "e" }, @@ -266,8 +267,8 @@ TEST_CASE("Complex Addition Associativity With Variables", "[Add][Associativity] const Oasis::Add<> add { Oasis::Real { 1.0 }, Oasis::Multiply { - Oasis::Add { - Oasis::Variable {"x"}, + Oasis::Add { + Oasis::Variable { "x" }, Oasis::Real { 1.0 } }, Oasis::Log { Oasis::Variable { "e" }, @@ -278,8 +279,8 @@ TEST_CASE("Complex Addition Associativity With Variables", "[Add][Associativity] const Oasis::Add<> expected { Oasis::Real { 1.0 }, Oasis::Multiply { - Oasis::Add { - Oasis::Variable {"x"}, + Oasis::Add { + Oasis::Variable { "x" }, Oasis::Real { 1.0 } }, Oasis::Log { Oasis::Variable { "e" }, diff --git a/tests/BinaryExpressionTests.cpp b/tests/BinaryExpressionTests.cpp index 87cd97fe..281f7822 100644 --- a/tests/BinaryExpressionTests.cpp +++ b/tests/BinaryExpressionTests.cpp @@ -8,10 +8,10 @@ #include "Oasis/Negate.hpp" #include "Oasis/Real.hpp" #include "Oasis/RecursiveCast.hpp" -#include "Oasis/Variable.hpp" #include "Oasis/SimplifyVisitor.hpp" +#include "Oasis/Variable.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Recursive Cast Considers Commutative Property", "[Symbolic]") { @@ -225,14 +225,15 @@ TEST_CASE("Equals follows associativity and commutativity") TEST_CASE("Substitute Binary", "[Substitute]") { Oasis::Add> before { - Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Variable { "x" } }, - Oasis::Multiply { - Oasis::Real { 3.0 }, - Oasis::Variable { "x" } } }; // 2x+3x - - auto after = before.Substitute(Oasis::Variable { "x" }, Oasis::Real { 4.0 }); // after should some std::unique_ptr such that it equals 2(4) + 3(4) - Oasis::Real twenty {20}; + Oasis::Multiply { + Oasis::Real { 2.0 }, + Oasis::Variable { "x" } }, + Oasis::Multiply { + Oasis::Real { 3.0 }, + Oasis::Variable { "x" } } + }; // 2x+3x + + auto after = before.Substitute(Oasis::Variable { "x" }, Oasis::Real { 4.0 }); // after should some std::unique_ptr such that it equals 2(4) + 3(4) + Oasis::Real twenty { 20 }; REQUIRE(after->Equals(*(twenty.Accept(simplifyVisitor).value()))); } \ No newline at end of file diff --git a/tests/DifferentiateTests.cpp b/tests/DifferentiateTests.cpp index da762f44..bd5fcce8 100644 --- a/tests/DifferentiateTests.cpp +++ b/tests/DifferentiateTests.cpp @@ -3,19 +3,21 @@ // #include "catch2/catch_test_macros.hpp" +#include "Common.hpp" #include "Oasis/Add.hpp" +#include "Oasis/Derivative.hpp" +#include "Oasis/DifferentiateVisitor.hpp" #include "Oasis/Divide.hpp" +#include "Oasis/EulerNumber.hpp" #include "Oasis/Exponent.hpp" +#include "Oasis/Log.hpp" #include "Oasis/Multiply.hpp" #include "Oasis/Real.hpp" +#include "Oasis/SimplifyVisitor.hpp" #include "Oasis/Subtract.hpp" #include "Oasis/Variable.hpp" -#include "Oasis/Derivative.hpp" -#include "Oasis/Log.hpp" -#include "Oasis/EulerNumber.hpp" -#include "Oasis/SimplifyVisitor.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Differentiate Nonzero number", "[Differentiate][Real][Nonzero]") { @@ -41,7 +43,7 @@ TEST_CASE("Differentiate Zero", "[Differentiate][Real][Zero]") TEST_CASE("Differentiate Same Variable", "[Differentiate][Variable][Same]") { Oasis::Variable var { "x" }; - Oasis::Real result {1.0}; + Oasis::Real result { 1.0 }; auto integrated = var.Differentiate(var); REQUIRE(result.Equals(*integrated)); @@ -64,7 +66,8 @@ TEST_CASE("Differentiate Power Rule", "[Differentiate][Exponent][Power]") Oasis::Multiply, Oasis::Real> diff1 { Oasis::Multiply { Oasis::Exponent { Oasis::Variable { var.GetName() }, Oasis::Real { 2.0f } }, - Oasis::Real { 3.0f } }}; + Oasis::Real { 3.0f } } + }; auto ptr = diff1.Accept(simplifyVisitor).value(); auto diffed = differentiate.Differentiate(var); @@ -75,7 +78,7 @@ TEST_CASE("Differentiate Constant Rule Multiply", "[Differentiate][Multiply][Con { Oasis::Variable var { "x" }; Oasis::Multiply diff1 { Oasis::Real { 3.0f }, Oasis::Variable { var.GetName() } }; - Oasis::Real three {3.0}; + Oasis::Real three { 3.0 }; auto ptr = three.Accept(simplifyVisitor).value(); auto diffed = diff1.Differentiate(var); @@ -86,7 +89,7 @@ TEST_CASE("Differentiate Constant Rule Divide", "[Differentiate][Divide][Constan { Oasis::Variable var { "x" }; Oasis::Divide diff1 { Oasis::Variable { var.GetName() }, Oasis::Real { 2.0f } }; - Oasis::Real half {0.5f}; + Oasis::Real half { 0.5f }; auto diffed = diff1.Differentiate(var); auto simplified = diffed->Accept(simplifyVisitor).value(); REQUIRE((simplified->Equals(*(half.Accept(simplifyVisitor).value())))); @@ -95,10 +98,12 @@ TEST_CASE("Differentiate Constant Rule Divide", "[Differentiate][Divide][Constan TEST_CASE("Differentiate Add Rule Different Terms", "[Differentiate][Add][Different]") { Oasis::Variable var { "x" }; - Oasis::Adddiff1 { Oasis::Variable { var.GetName() }, Oasis::Real { 2.0f } }; + Oasis::Add diff1 { Oasis::Variable { var.GetName() }, Oasis::Real { 2.0f } }; - Oasis::Real one {1}; - auto diffed = diff1.Differentiate(var); + Oasis::DifferentiateVisitor differentiateVisitor { var.Copy() }; + + Oasis::Real one { 1 }; + auto diffed = diff1.Accept(differentiateVisitor).value(); auto simplified = diffed->Accept(simplifyVisitor).value(); REQUIRE(simplified->Equals(*(one.Accept(simplifyVisitor).value()))); @@ -108,7 +113,7 @@ TEST_CASE("Differentiate Subtract Rule Different Terms", "[Differentiate][Subtra { Oasis::Variable var { "x" }; Oasis::Subtract diff1 { Oasis::Variable { var.GetName() }, Oasis::Real { 2.0f } }; - Oasis::Real one {1}; + Oasis::Real one { 1 }; auto diffed = diff1.Differentiate(var); auto simplified = diffed->Accept(simplifyVisitor).value(); @@ -120,7 +125,7 @@ TEST_CASE("Differentiate Add Rule Like Terms", "[Differentiate][Add][Like]") Oasis::Variable var { "x" }; Oasis::Add diff1 { Oasis::Variable { var.GetName() }, Oasis::Variable { var.GetName() } }; - Oasis::Real two {2}; + Oasis::Real two { 2 }; auto diffed = diff1.Differentiate(var); auto simplified = diffed->Accept(simplifyVisitor).value(); @@ -130,26 +135,17 @@ TEST_CASE("Differentiate Add Rule Like Terms", "[Differentiate][Add][Like]") TEST_CASE("Differentiate Quotient Rule Like Terms", "[Differentiate][Divide][Like]") { - Oasis::Variable var{"x"}; // dx + Oasis::Variable var { "x" }; // dx // derivative of [(x + 2)/(x + 3)] - Oasis::Divide, Oasis::Add> diff1 - {Oasis::Add {Oasis::Variable {var.GetName() }, - Oasis::Real {2}},Oasis::Add - {Oasis::Variable {var.GetName() }, Oasis::Real - {3}}}; - Oasis::Divide> answer - {Oasis::Subtract, Oasis::Real>> - {Oasis::Multiply, Oasis::Real> - {Oasis::Add {Oasis::Variable {var.GetName()}, Oasis::Real {3}}, - Oasis::Real {1}}, - Oasis::Multiply, Oasis::Real>{ - Oasis::Add {Oasis::Variable {var.GetName()}, Oasis::Real {2}}, - Oasis::Real {1}}}, - Oasis::Multiply{Oasis::Add - {Oasis::Variable {var.GetName() }, Oasis::Real - {3}}, Oasis::Add - {Oasis::Variable {var.GetName() }, Oasis::Real - {3}}}}; + Oasis::Divide, Oasis::Add> diff1 { Oasis::Add { Oasis::Variable { var.GetName() }, + Oasis::Real { 2 } }, + Oasis::Add { Oasis::Variable { var.GetName() }, Oasis::Real { 3 } } }; + Oasis::Divide> answer { Oasis::Subtract, Oasis::Real>> { Oasis::Multiply, Oasis::Real> { Oasis::Add { Oasis::Variable { var.GetName() }, Oasis::Real { 3 } }, + Oasis::Real { 1 } }, + Oasis::Multiply, Oasis::Real> { + Oasis::Add { Oasis::Variable { var.GetName() }, Oasis::Real { 2 } }, + Oasis::Real { 1 } } }, + Oasis::Multiply { Oasis::Add { Oasis::Variable { var.GetName() }, Oasis::Real { 3 } }, Oasis::Add { Oasis::Variable { var.GetName() }, Oasis::Real { 3 } } } }; auto diffed = diff1.Differentiate(var); auto simplified = diffed->Accept(simplifyVisitor).value(); @@ -160,26 +156,22 @@ TEST_CASE("Differentiate Quotient Rule Like Terms", "[Differentiate][Divide][Lik TEST_CASE("Differentiate Multiple Variables Differentiate", "[Differentiate][Multiply][Different]") { - Oasis::Variable x {"x"}; - Oasis::Variable y {"y"}; - Oasis::Multiply xy - {Oasis::Variable {x.GetName()}, Oasis::Variable {y.GetName()}}; + Oasis::Variable x { "x" }; + Oasis::Variable y { "y" }; + Oasis::Multiply xy { Oasis::Variable { x.GetName() }, Oasis::Variable { y.GetName() } }; auto diffed = xy.Differentiate(x); auto simplified = diffed->Accept(simplifyVisitor).value(); - REQUIRE(simplified->Equals(*(y.Accept(simplifyVisitor).value()))); + REQUIRE(simplified->Equals(*(std::move(y.Accept(simplifyVisitor)).value()))); } TEST_CASE("Differentiate Multiple Variables + Real Differentiate", "[Differentiate][Multiply][Different]") { - Oasis::Variable x {"x"}; - Oasis::Variable y {"y"}; - Oasis::Multiply xy - {Oasis::Variable {x.GetName()}, Oasis::Variable {y.GetName()}}; - - Oasis::Multiply threexy - {Oasis::Real {3}, *(xy.Copy())}; - Oasis::Multiply threex - {Oasis::Real{3}, Oasis::Variable{x.GetName()}}; + Oasis::Variable x { "x" }; + Oasis::Variable y { "y" }; + Oasis::Multiply xy { Oasis::Variable { x.GetName() }, Oasis::Variable { y.GetName() } }; + + Oasis::Multiply threexy { Oasis::Real { 3 }, *(xy.Copy()) }; + Oasis::Multiply threex { Oasis::Real { 3 }, Oasis::Variable { x.GetName() } }; auto diffed = threexy.Differentiate(y); auto simplified = diffed->Accept(simplifyVisitor).value(); REQUIRE(simplified->Equals(*(threex.Accept(simplifyVisitor).value()))); @@ -187,97 +179,95 @@ TEST_CASE("Differentiate Multiple Variables + Real Differentiate", "[Differentia TEST_CASE("Derivative Wrapper Class Add", "[Differentiate][Add][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative, Oasis::Variable> diff1 - {Oasis::Add {Oasis::Variable {x.GetName()}, - Oasis::Real{2}}, Oasis::Variable {x.GetName()}}; - Oasis::Real one {1}; + Oasis::Variable x { "x" }; + Oasis::Derivative, Oasis::Variable> diff1 { Oasis::Add { Oasis::Variable { x.GetName() }, + Oasis::Real { 2 } }, + Oasis::Variable { x.GetName() } }; + Oasis::Real one { 1 }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(one.Accept(simplifyVisitor).value()))); } TEST_CASE("Derivative Wrapper Class Subtract", "[Differentiate][Subtract][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative, Oasis::Variable> diff1 - {Oasis::Subtract {Oasis::Variable {x.GetName()}, - Oasis::Real{2}}, Oasis::Variable {x.GetName()}}; - Oasis::Real one {1}; + Oasis::Variable x { "x" }; + Oasis::Derivative, Oasis::Variable> diff1 { Oasis::Subtract { Oasis::Variable { x.GetName() }, + Oasis::Real { 2 } }, + Oasis::Variable { x.GetName() } }; + Oasis::Real one { 1 }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(one.Accept(simplifyVisitor).value()))); } TEST_CASE("Derivative Wrapper Class Multiply", "[Differentiate][Multiply][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative, Oasis::Variable> diff1 - {Oasis::Multiply {Oasis::Variable {x.GetName()}, - Oasis::Real{2}}, Oasis::Variable {x.GetName()}}; - Oasis::Real two {2}; + Oasis::Variable x { "x" }; + Oasis::Derivative, Oasis::Variable> diff1 { Oasis::Multiply { Oasis::Variable { x.GetName() }, + Oasis::Real { 2 } }, + Oasis::Variable { x.GetName() } }; + Oasis::Real two { 2 }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(two.Accept(simplifyVisitor).value()))); } TEST_CASE("Derivative Wrapper Class Divide", "[Differentiate][Divide][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative, Oasis::Variable> diff1 - {Oasis::Divide {Oasis::Variable {x.GetName()}, - Oasis::Real{2}}, Oasis::Variable {x.GetName()}}; - Oasis::Real half {0.5f}; + Oasis::Variable x { "x" }; + Oasis::Derivative, Oasis::Variable> diff1 { Oasis::Divide { Oasis::Variable { x.GetName() }, + Oasis::Real { 2 } }, + Oasis::Variable { x.GetName() } }; + Oasis::Real half { 0.5f }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(half.Accept(simplifyVisitor).value()))); } TEST_CASE("Derivative Wrapper Class Real", "[Differentiate][Real][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative diff1 - {Oasis::Real {2}, Oasis::Variable {x.GetName()}}; - Oasis::Real zero {0}; + Oasis::Variable x { "x" }; + Oasis::Derivative diff1 { Oasis::Real { 2 }, Oasis::Variable { x.GetName() } }; + Oasis::Real zero { 0 }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(zero.Accept(simplifyVisitor).value()))); } TEST_CASE("Derivative Wrapper Class Variable", "[Differentiate][Variable][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative diff1 - {Oasis::Variable {x.GetName()}, Oasis::Variable {x.GetName()}}; - Oasis::Real one {1}; + Oasis::Variable x { "x" }; + Oasis::Derivative diff1 { Oasis::Variable { x.GetName() }, Oasis::Variable { x.GetName() } }; + Oasis::Real one { 1 }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(one.Accept(simplifyVisitor).value()))); } TEST_CASE("Derivative Wrapper Class Exponent", "[Differentiate][Exponent][Like]") { - Oasis::Variable x {"x"}; - Oasis::Derivative, Oasis::Variable> diff1 - {Oasis::Exponent {Oasis::Variable {x.GetName()}, - Oasis::Real{2}}, Oasis::Variable {x.GetName()}}; - Oasis::Multiply twox {Oasis::Variable {x.GetName()}, Oasis::Real {2}}; + Oasis::Variable x { "x" }; + Oasis::Derivative, Oasis::Variable> diff1 { Oasis::Exponent { Oasis::Variable { x.GetName() }, + Oasis::Real { 2 } }, + Oasis::Variable { x.GetName() } }; + Oasis::Multiply twox { Oasis::Variable { x.GetName() }, Oasis::Real { 2 } }; auto diffed = diff1.Accept(simplifyVisitor).value(); REQUIRE(diffed->Equals(*(twox.Accept(simplifyVisitor).value()))); } TEST_CASE("Product Rule", "[Differentiate][Product]") { - Oasis::Variable f{"x"}; - Oasis::Multiply g{Oasis::Real{6.0}, Oasis::Variable{"x"}}; - Oasis::Derivative diff{Oasis::Multiply{f, g}, Oasis::Variable{"x"}}; + Oasis::Variable f { "x" }; + Oasis::Multiply g { Oasis::Real { 6.0 }, Oasis::Variable { "x" } }; + Oasis::Derivative diff { Oasis::Multiply { f, g }, Oasis::Variable { "x" } }; auto simplified = diff.Accept(simplifyVisitor).value(); - Oasis::Multiply expected{Oasis::Real{12.0}, Oasis::Variable{"x"}}; + Oasis::Multiply expected { Oasis::Real { 12.0 }, Oasis::Variable { "x" } }; REQUIRE(simplified->Equals(expected)); } TEST_CASE("Natural Exponential Derivative", "[Derivative][Exponent][Euler's Number]") { - Oasis::Exponent exp{Oasis::EulerNumber{}, Oasis::Variable{"x"}}; - Oasis::Exponent exp2{Oasis::EulerNumber{}, Oasis::Multiply{Oasis::Real{2.0},Oasis::Variable{"x"}}}; - Oasis::Derivative diffExp{exp, Oasis::Variable{"x"}}; - Oasis::Derivative diffExp2{exp2, Oasis::Variable{"x"}}; - Oasis::Multiply expected2{Oasis::Real{2.0}, exp2}; + Oasis::Exponent exp { Oasis::EulerNumber {}, Oasis::Variable { "x" } }; + Oasis::Exponent exp2 { Oasis::EulerNumber {}, Oasis::Multiply { Oasis::Real { 2.0 }, Oasis::Variable { "x" } } }; + Oasis::Derivative diffExp { exp, Oasis::Variable { "x" } }; + Oasis::Derivative diffExp2 { exp2, Oasis::Variable { "x" } }; + Oasis::Multiply expected2 { Oasis::Real { 2.0 }, exp2 }; auto simplified = diffExp.Accept(simplifyVisitor).value(); auto simplified2 = diffExp2.Accept(simplifyVisitor).value(); @@ -287,75 +277,84 @@ TEST_CASE("Natural Exponential Derivative", "[Derivative][Exponent][Euler's Numb TEST_CASE("Natural Logarithm Derivative", "[Derivative][Logarithm][Euler's Number]") { - Oasis::Derivative diffLog{ - Oasis::Log{Oasis::EulerNumber{},Oasis::Multiply{Oasis::Real{6},Oasis::Variable{"x"}}}, Oasis::Variable{"x"}}; + Oasis::Derivative diffLog { + Oasis::Log { Oasis::EulerNumber {}, Oasis::Multiply { Oasis::Real { 6 }, Oasis::Variable { "x" } } }, Oasis::Variable { "x" } + }; auto raw = diffLog.Accept(simplifyVisitor); auto diff = std::move(raw).value(); - Oasis::Divide expected{Oasis::Real{1.0}, Oasis::Variable{"x"}}; + Oasis::Divide expected { Oasis::Real { 1.0 }, Oasis::Variable { "x" } }; REQUIRE(diff->Equals(expected)); } TEST_CASE("Real Base Logarithm Derivative", "[Derivative][Logarithm][Euler's Real]") { - Oasis::Derivative diffLog{ - Oasis::Log{Oasis::Real{10.0},Oasis::Multiply{Oasis::Real{6},Oasis::Variable{"x"}}}, Oasis::Variable{"x"}}; + Oasis::Derivative diffLog { + Oasis::Log { Oasis::Real { 10.0 }, Oasis::Multiply { Oasis::Real { 6 }, Oasis::Variable { "x" } } }, Oasis::Variable { "x" } + }; auto diff = diffLog.Accept(simplifyVisitor).value(); - Oasis::Divide expected{Oasis::Real{1.0}, Oasis::Multiply{Oasis::Variable{"x"}, - Oasis::Log{Oasis::EulerNumber{}, Oasis::Real{10.0}}}}; + Oasis::Divide expected { Oasis::Real { 1.0 }, Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Log { Oasis::EulerNumber {}, Oasis::Real { 10.0 } } } }; REQUIRE(diff->Equals(*expected.Accept(simplifyVisitor).value())); } TEST_CASE("Variable Base Logarithm Derivative", "[Derivative][Logarithm][Variable]") { - Oasis::Derivative diffLog{ - Oasis::Log{Oasis::Variable{"y"},Oasis::Multiply{Oasis::Real{6},Oasis::Variable{"x"}}}, Oasis::Variable{"x"}}; + Oasis::Derivative diffLog { + Oasis::Log { Oasis::Variable { "y" }, Oasis::Multiply { Oasis::Real { 6 }, Oasis::Variable { "x" } } }, Oasis::Variable { "x" } + }; auto diff = diffLog.Accept(simplifyVisitor).value(); - Oasis::Divide expected{Oasis::Real{1.0}, Oasis::Multiply{Oasis::Variable{"x"}, - Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"y"}}}}; + Oasis::Divide expected { Oasis::Real { 1.0 }, Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "y" } } } }; REQUIRE(diff->Equals(expected)); } TEST_CASE("Any Base Exponential Derivative", "[Derivative][Exponent]") { - Oasis::Exponent exp{Oasis::Variable{"a"}, Oasis::Multiply{Oasis::Real{2.0},Oasis::Variable{"x"}}}; - Oasis::Derivative diffExp{exp, Oasis::Variable{"x"}}; - Oasis::Multiply expected{Oasis::Multiply{Oasis::Real{2.0}, exp}, Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"a"}}}; + Oasis::Exponent exp { Oasis::Variable { "a" }, Oasis::Multiply { Oasis::Real { 2.0 }, Oasis::Variable { "x" } } }; + Oasis::Derivative diffExp { exp, Oasis::Variable { "x" } }; + Oasis::Multiply expected { Oasis::Multiply { Oasis::Real { 2.0 }, exp }, Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "a" } } }; auto simplified = diffExp.Accept(simplifyVisitor).value(); REQUIRE(simplified->Equals(expected)); } TEST_CASE("Variable Base Exponential Derivative", "[Derivative][Exponent]") { - Oasis::Exponent exp{Oasis::Variable{"x"}, Oasis::Multiply{Oasis::Real{2.0},Oasis::Variable{"x"}}}; - Oasis::Derivative diffExp{exp, Oasis::Variable{"x"}}; - Oasis::Multiply expected{exp , Oasis::Add{ Oasis::Multiply {Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"x"}}, - Oasis::Real{2.0}},Oasis::Real{2.0}},}; + Oasis::Exponent exp { Oasis::Variable { "x" }, Oasis::Multiply { Oasis::Real { 2.0 }, Oasis::Variable { "x" } } }; + Oasis::Derivative diffExp { exp, Oasis::Variable { "x" } }; + Oasis::Multiply expected { + exp, + Oasis::Add { Oasis::Multiply { Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "x" } }, + Oasis::Real { 2.0 } }, + Oasis::Real { 2.0 } }, + }; auto simplified = diffExp.Accept(simplifyVisitor).value(); REQUIRE(simplified->Equals(expected)); } TEST_CASE("General Exponential Derivative", "[Derivative][Exponent]") { - Oasis::Exponent exp{ Oasis::Add { Oasis::Variable{"x"}, Oasis::Real{3.0} }, - Oasis::Multiply{Oasis::Real{4.0},Oasis::Variable{"x"}}}; - Oasis::Derivative diffExp{exp, Oasis::Variable{"x"}}; - Oasis::Multiply expected{ exp , - Oasis::Add{ - Oasis::Divide { Oasis::Multiply {Oasis::Real{4.0},Oasis::Variable{"x"} } , - Oasis::Add { Oasis::Variable{"x"}, Oasis::Real{3.0} } } , - Oasis::Multiply { Oasis::Real{4.0} , - Oasis::Log{Oasis::EulerNumber{}, - Oasis::Add { Oasis::Variable{"x"}, Oasis::Real{3.0} }}} } }; - auto simplified = diffExp.Accept(simplifyVisitor).value(); - REQUIRE(simplified->Equals(expected)); + Oasis::Exponent exp { Oasis::Add { Oasis::Variable { "x" }, Oasis::Real { 3.0 } }, + Oasis::Multiply { Oasis::Real { 4.0 }, Oasis::Variable { "x" } } }; + Oasis::Derivative diffExp { exp, Oasis::Variable { "x" } }; + Oasis::Multiply expected { exp, + Oasis::Add { + Oasis::Divide { Oasis::Multiply { Oasis::Real { 4.0 }, Oasis::Variable { "x" } }, + Oasis::Add { Oasis::Variable { "x" }, Oasis::Real { 3.0 } } }, + Oasis::Multiply { Oasis::Real { 4.0 }, + Oasis::Log { Oasis::EulerNumber {}, + Oasis::Add { Oasis::Variable { "x" }, Oasis::Real { 3.0 } } } } } }; + const auto& simplified = diffExp.Accept(simplifyVisitor); + const auto& simplifiedValue = *simplified.value(); + const auto& simplifiedExpected = expected.Accept(simplifyVisitor); + const auto& simplifiedExpectedValue = *simplifiedExpected.value(); + OASIS_CAPTURE_WITH_SERIALIZER(simplifiedExpectedValue); + REQUIRE(simplifiedValue.Equals(simplifiedExpectedValue)); } TEST_CASE("Expression Base Exponential Derivative", "[Derivative][Exponent]") { - Oasis::Exponent exp{ Oasis::Add { Oasis::Variable{"x"}, Oasis::Real{3.0} } , Oasis::Real{2.0}}; - Oasis::Derivative diffExp{exp, Oasis::Variable{"x"}}; + Oasis::Exponent exp { Oasis::Add { Oasis::Variable { "x" }, Oasis::Real { 3.0 } }, Oasis::Real { 2.0 } }; + Oasis::Derivative diffExp { exp, Oasis::Variable { "x" } }; - Oasis::Multiply expected{ Oasis::Add {Oasis::Variable{"x"} , Oasis::Real {3.0} }, Oasis::Real{ 2.0} }; + Oasis::Multiply expected { Oasis::Add { Oasis::Variable { "x" }, Oasis::Real { 3.0 } }, Oasis::Real { 2.0 } }; auto simplified = diffExp.Accept(simplifyVisitor).value(); REQUIRE(simplified->Equals(expected)); diff --git a/tests/DivideTests.cpp b/tests/DivideTests.cpp index 1e8a66a8..21b50260 100644 --- a/tests/DivideTests.cpp +++ b/tests/DivideTests.cpp @@ -4,16 +4,16 @@ #include "catch2/catch_test_macros.hpp" +#include "Oasis/Add.hpp" #include "Oasis/Divide.hpp" +#include "Oasis/Exponent.hpp" +#include "Oasis/Multiply.hpp" #include "Oasis/Real.hpp" #include "Oasis/RecursiveCast.hpp" -#include "Oasis/Variable.hpp" -#include "Oasis/Multiply.hpp" -#include "Oasis/Exponent.hpp" -#include "Oasis/Add.hpp" #include "Oasis/SimplifyVisitor.hpp" +#include "Oasis/Variable.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Division", "[Divide]") { @@ -38,25 +38,22 @@ TEST_CASE("Symbolic Division, equal variables", "[Division][Symbolic]") Oasis::Real { 2.0 }, Oasis::Variable { "x" } }, Oasis::Multiply { - Oasis::Real { 1.0 }, + Oasis::Real { 1.0 }, Oasis::Variable { "x" } } }; - const Oasis::Divide div2 { Oasis::Multiply<> { Oasis::Real { 2.0 }, - Oasis::Variable{ "z" }, - Oasis::Variable{ "y" }, - Oasis::Variable{ "x" } - }, + Oasis::Variable { "z" }, + Oasis::Variable { "y" }, + Oasis::Variable { "x" } }, Oasis::Multiply<> { Oasis::Real { 1.0 }, - Oasis::Variable{ "y" }, - Oasis::Variable{ "x" }, - Oasis::Variable{ "z" } - } - }; + Oasis::Variable { "y" }, + Oasis::Variable { "x" }, + Oasis::Variable { "z" } } + }; auto simplified = div.Accept(simplifyVisitor).value(); REQUIRE(simplified->Equals(Oasis::Real { 2.0 })); @@ -65,7 +62,6 @@ TEST_CASE("Symbolic Division, equal variables", "[Division][Symbolic]") REQUIRE(simplified2->Equals(Oasis::Real { 2.0 })); } - TEST_CASE("Symbolic Division, unequal variables", "[Division][Symbolic]") { Oasis::Divide div { @@ -73,61 +69,60 @@ TEST_CASE("Symbolic Division, unequal variables", "[Division][Symbolic]") Oasis::Real { 4.0 }, Oasis::Multiply { Oasis::Variable { "z" }, - Oasis::Variable { "x" } }}, + Oasis::Variable { "x" } } }, Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Multiply { - Oasis::Variable { "y" }, - Oasis::Variable { "z" } }} - }; + Oasis::Real { 2.0 }, + Oasis::Multiply { + Oasis::Variable { "y" }, + Oasis::Variable { "z" } } } + }; auto simplified = div.Accept(simplifyVisitor).value(); REQUIRE(Oasis::Divide { Oasis::Multiply { Oasis::Real { 2.0 }, - Oasis::Variable { "x"} }, - Oasis::Variable { "y" } }.Equals(*simplified)); + Oasis::Variable { "x" } }, + Oasis::Variable { "y" } } + .Equals(*simplified)); } - TEST_CASE("Symbolic Division of Expressions", "[Division][Symbolic]") { - //4(z^2+1)(x+1)/2(x+1)=2(z^2+1) + // 4(z^2+1)(x+1)/2(x+1)=2(z^2+1) Oasis::Divide div { - Oasis::Multiply{ + Oasis::Multiply { Oasis::Multiply { Oasis::Add { Oasis::Variable { "x" }, Oasis::Real { 1 } }, - Oasis::Add{ + Oasis::Add { Oasis::Exponent { Oasis::Variable { "z" }, Oasis::Real { 2 } }, - Oasis::Real{ 1 }}}, - Oasis::Real { 4.0 } - }, + Oasis::Real { 1 } } }, + Oasis::Real { 4.0 } }, Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Add { - Oasis::Variable { "x" }, - Oasis::Real { 1 } }} - }; + Oasis::Real { 2.0 }, + Oasis::Add { + Oasis::Variable { "x" }, + Oasis::Real { 1 } } } + }; auto simplified = div.Accept(simplifyVisitor).value(); REQUIRE(Oasis::Multiply { - Oasis::Real{ 2 }, - Oasis::Add{ + Oasis::Real { 2 }, + Oasis::Add { Oasis::Exponent { Oasis::Variable { "z" }, Oasis::Real { 2 } }, - Oasis::Real{ 1 }}, - }.Equals(*simplified)); + Oasis::Real { 1 } }, + } + .Equals(*simplified)); } - TEST_CASE("Symbolic Division, unequal exponents", "[Division][Symbolic]") { Oasis::Divide div { @@ -135,24 +130,24 @@ TEST_CASE("Symbolic Division, unequal exponents", "[Division][Symbolic]") Oasis::Real { 4.0 }, Oasis::Exponent { Oasis::Variable { "z" }, - Oasis::Real { 2 } }}, + Oasis::Real { 2 } } }, Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Multiply { - Oasis::Variable { "y" }, - Oasis::Variable { "z" } }} - }; + Oasis::Real { 2.0 }, + Oasis::Multiply { + Oasis::Variable { "y" }, + Oasis::Variable { "z" } } } + }; auto simplified = div.Accept(simplifyVisitor).value(); REQUIRE(Oasis::Divide { Oasis::Multiply { Oasis::Real { 2.0 }, - Oasis::Variable { "z"} }, - Oasis::Variable { "y" } }.Equals(*simplified)); + Oasis::Variable { "z" } }, + Oasis::Variable { "y" } } + .Equals(*simplified)); } - TEST_CASE("Symbolic Division, equal exponents", "[Division][Symbolic]") { Oasis::Divide div { @@ -160,13 +155,13 @@ TEST_CASE("Symbolic Division, equal exponents", "[Division][Symbolic]") Oasis::Real { 4.0 }, Oasis::Exponent { Oasis::Variable { "z" }, - Oasis::Real { 3 } }}, + Oasis::Real { 3 } } }, Oasis::Multiply { - Oasis::Real { 2.0 }, - Oasis::Multiply { - Oasis::Variable { "y" }, - Oasis::Variable { "z" } }} - }; + Oasis::Real { 2.0 }, + Oasis::Multiply { + Oasis::Variable { "y" }, + Oasis::Variable { "z" } } } + }; auto simplified = div.Accept(simplifyVisitor).value(); @@ -176,7 +171,8 @@ TEST_CASE("Symbolic Division, equal exponents", "[Division][Symbolic]") Oasis::Exponent { Oasis::Variable { "z" }, Oasis::Real { 2 } } }, - Oasis::Variable { "y" } }.Equals(*simplified)); + Oasis::Variable { "y" } } + .Equals(*simplified)); } TEST_CASE("Division of equal variables", "[Division][Symbolic]") @@ -188,7 +184,6 @@ TEST_CASE("Division of equal variables", "[Division][Symbolic]") REQUIRE(Oasis::Real { 1 }.Equals(*simplified)); } - TEST_CASE("Generalized Division", "[Divide][Generalized]") { Oasis::Divide subtract { @@ -210,10 +205,9 @@ TEST_CASE("Divide Operator Overload", "[Divide][Operator Overload]") const std::unique_ptr a = std::make_unique(1.0); const std::unique_ptr b = std::make_unique(2.0); - const auto sum = b/a; + const auto sum = b / a; auto realSum = Oasis::RecursiveCast(*sum); REQUIRE(realSum != nullptr); REQUIRE(realSum->GetValue() == 2.0); - } \ No newline at end of file diff --git a/tests/ExponentTests.cpp b/tests/ExponentTests.cpp index 827ab282..3a040c2d 100644 --- a/tests/ExponentTests.cpp +++ b/tests/ExponentTests.cpp @@ -10,11 +10,11 @@ #include "Oasis/Multiply.hpp" #include "Oasis/Negate.hpp" #include "Oasis/Real.hpp" +#include "Oasis/SimplifyVisitor.hpp" #include "Oasis/Subtract.hpp" #include "Oasis/Variable.hpp" -#include "Oasis/SimplifyVisitor.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Zero Rule", "[Exponent][Zero]") { @@ -191,25 +191,25 @@ TEST_CASE("Addition of Exponents", "[Add][Exponent][Symbolic]") Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified)); + .Equals(*simplified)); REQUIRE(Oasis::Multiply { Oasis::Real { 3.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified2)); + .Equals(*simplified2)); REQUIRE(Oasis::Multiply { Oasis::Real { 3.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified3)); + .Equals(*simplified3)); REQUIRE(Oasis::Multiply { Oasis::Real { 4.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified4)); + .Equals(*simplified4)); } TEST_CASE("Variable Multiplication", "[Exponent][Variable][Multiplication]") @@ -251,13 +251,13 @@ TEST_CASE("Variable Multiplication", "[Exponent][Variable][Multiplication]") REQUIRE(Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } }.Equals(*simplified)); REQUIRE(Oasis::Multiply> { Oasis::Real { 5.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified2)); + .Equals(*simplified2)); REQUIRE(Oasis::Multiply> { Oasis::Real { 5.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified3)); + .Equals(*simplified3)); REQUIRE(Oasis::Multiply> { Oasis::Real { 24.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified4)); + .Equals(*simplified4)); } TEST_CASE("Variable with power Multiplication", "[Exponent][Variable][Multiplication]") @@ -355,19 +355,19 @@ TEST_CASE("Variable with power Multiplication", "[Exponent][Variable][Multiplica REQUIRE(Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 5.0 } }.Equals(*simplified3)); REQUIRE(Oasis::Multiply> { Oasis::Real { 3.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 4.0 } } } - .Equals(*simplified4)); + .Equals(*simplified4)); REQUIRE(Oasis::Multiply> { Oasis::Real { 3.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 4.0 } } } - .Equals(*simplified5)); + .Equals(*simplified5)); REQUIRE(Oasis::Multiply> { Oasis::Real { 6.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 3.0 } } } - .Equals(*simplified6)); + .Equals(*simplified6)); REQUIRE(Oasis::Multiply> { Oasis::Real { 3.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 4.0 } } } - .Equals(*simplified7)); + .Equals(*simplified7)); REQUIRE(Oasis::Multiply> { Oasis::Real { 6.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 4.0 } } } - .Equals(*simplified8)); + .Equals(*simplified8)); } TEST_CASE("Subtraction of Exponents", "[Subtract][Exponent][Symbolic]") @@ -423,22 +423,25 @@ TEST_CASE("Subtraction of Exponents", "[Subtract][Exponent][Symbolic]") REQUIRE(Oasis::Real { 0.0 }.Equals(*simplified)); REQUIRE((Oasis::Multiply { - Oasis::Real { 1.0 }, - Oasis::Exponent { - Oasis::Variable { "x" }, - Oasis::Real { 2.0 } } }).Accept(simplifyVisitor).value()->Equals(*simplified2)); + Oasis::Real { 1.0 }, + Oasis::Exponent { + Oasis::Variable { "x" }, + Oasis::Real { 2.0 } } }) + .Accept(simplifyVisitor) + .value() + ->Equals(*simplified2)); REQUIRE(Oasis::Multiply { Oasis::Real { -1.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified3)); + .Equals(*simplified3)); REQUIRE(Oasis::Multiply { Oasis::Real { 4.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 2.0 } } } - .Equals(*simplified4)); + .Equals(*simplified4)); } TEST_CASE("Imaginary Exponent Rule", "[Imaginary][Exponent]") @@ -481,5 +484,5 @@ TEST_CASE("Imaginary Exponent Rule", "[Imaginary][Exponent]") REQUIRE(Oasis::Multiply { Oasis::Multiply { Oasis::Real { 2.0 }, Oasis::Exponent { Oasis::Variable { "x" }, Oasis::Real { 0.5 } } }, Oasis::Imaginary {} } - .Equals(*simplifiedimg)); + .Equals(*simplifiedimg)); } \ No newline at end of file diff --git a/tests/IntegrateTests.cpp b/tests/IntegrateTests.cpp index 4ef48f57..96ef3dde 100644 --- a/tests/IntegrateTests.cpp +++ b/tests/IntegrateTests.cpp @@ -7,11 +7,11 @@ #include "Oasis/Log.hpp" #include "Oasis/Multiply.hpp" #include "Oasis/Real.hpp" +#include "Oasis/SimplifyVisitor.hpp" #include "Oasis/Subtract.hpp" #include "Oasis/Variable.hpp" -#include "Oasis/SimplifyVisitor.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Integrate Nonzero number", "[Integrate][Real][Nonzero]") { diff --git a/tests/LinearTests.cpp b/tests/LinearTests.cpp index 4af88be4..ef7928dc 100644 --- a/tests/LinearTests.cpp +++ b/tests/LinearTests.cpp @@ -65,7 +65,7 @@ TEST_CASE("Linear Creation", "[Linear]") TEST_CASE("Linear Solve with subtraction", "[Linear][Subtract]") { - Oasis::Add add1{ // 4x - 7y + -5 + Oasis::Add add1 { // 4x - 7y + -5 Oasis::Subtract { Oasis::Multiply { @@ -111,7 +111,7 @@ TEST_CASE("Linear Solve with subtraction", "[Linear][Subtract]") } // commented out test case to prevent problems with factoring and distributing -//TEST_CASE("Linear Solve with subtraction 2", "[Linear][Subtract]") +// TEST_CASE("Linear Solve with subtraction 2", "[Linear][Subtract]") //{ // Oasis::Add add1{ // ((4x - (7y + 5)) + z) // Oasis::Subtract{ diff --git a/tests/LogTests.cpp b/tests/LogTests.cpp index 54e0266e..79f2d938 100644 --- a/tests/LogTests.cpp +++ b/tests/LogTests.cpp @@ -7,21 +7,21 @@ #include "Oasis/Add.hpp" #include "Oasis/Divide.hpp" -#include "Oasis/Exponent.hpp" #include "Oasis/EulerNumber.hpp" +#include "Oasis/Exponent.hpp" #include "Oasis/Integral.hpp" #include "Oasis/Log.hpp" #include "Oasis/Multiply.hpp" #include "Oasis/Real.hpp" #include "Oasis/RecursiveCast.hpp" +#include "Oasis/SimplifyVisitor.hpp" #include "Oasis/Subtract.hpp" #include "Oasis/Undefined.hpp" #include "Oasis/Variable.hpp" -#include "Oasis/SimplifyVisitor.hpp" #define EPSILON 1E-6 -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Log with invalid base", "[Log][Invalid Base]") { @@ -54,7 +54,7 @@ TEST_CASE("Log with invalid argument", "[Log][Invalid Argument]") TEST_CASE("Log of Real Numbers", "[Log][Real]") { - //log[5](1) = 0 + // log[5](1) = 0 Oasis::Log base5of1 { Oasis::Real { 5.0 }, Oasis::Real { 1.0 } @@ -65,8 +65,8 @@ TEST_CASE("Log of Real Numbers", "[Log][Real]") auto simplifiedReal5_1 = dynamic_cast(*base5of1_Simplified); REQUIRE(simplifiedReal5_1.GetValue() == 0.0); - - //log[5](5) = 1 + + // log[5](5) = 1 Oasis::Log base5of5 { Oasis::Real { 5.0 }, Oasis::Real { 5.0 } @@ -78,7 +78,7 @@ TEST_CASE("Log of Real Numbers", "[Log][Real]") auto simplifiedReal5_5 = dynamic_cast(*base5of5_Simplified); REQUIRE_THAT(simplifiedReal5_5.GetValue(), Catch::Matchers::WithinAbs(1.0, EPSILON)); - //log[5](25) = 2 + // log[5](25) = 2 Oasis::Log base5of25 { Oasis::Real { 5.0 }, Oasis::Real { 25.0 } @@ -93,13 +93,12 @@ TEST_CASE("Log of Real Numbers", "[Log][Real]") TEST_CASE("Log of Exponentiation", "[Log][Exponent]") { - //log[5](5^x) = x + // log[5](5^x) = x Oasis::Log base5of5toX { Oasis::Real { 5.0 }, Oasis::Exponent { - Oasis::Real { 5.0 }, - Oasis::Variable { "x" } - } + Oasis::Real { 5.0 }, + Oasis::Variable { "x" } } }; auto base5of5toX_Simplified = base5of5toX.Accept(simplifyVisitor).value(); @@ -109,21 +108,19 @@ TEST_CASE("Log of Exponentiation", "[Log][Exponent]") REQUIRE_THAT(simplifiedSpecialized->GetMostSigOp().GetValue(), Catch::Matchers::WithinAbs(1.0, EPSILON)); REQUIRE(simplifiedSpecialized->GetLeastSigOp().Equals(Oasis::Variable { "x" })); - //log[5](x^x) = xlog[5](x) + // log[5](x^x) = xlog[5](x) Oasis::Log logOfExp { Oasis::Real { 5.0 }, Oasis::Exponent { - Oasis::Variable { "x" }, - Oasis::Variable { "x" } - } + Oasis::Variable { "x" }, + Oasis::Variable { "x" } } }; Oasis::Multiply logOfExpResult { Oasis::Variable { "x" }, Oasis::Log { Oasis::Real { 5.0 }, - Oasis::Variable { "x" } - } + Oasis::Variable { "x" } } }; auto logOfExp_Simplified = logOfExp.Accept(simplifyVisitor).value(); @@ -151,13 +148,15 @@ TEST_CASE("Sum of logs", "[Log][Add]") auto logOf4Simplified = dynamic_cast(*Oasis::Add { logOf2, - logOf2 - }.Accept(simplifyVisitor).value()); + logOf2 } + .Accept(simplifyVisitor) + .value()); auto logOf6Simplified = dynamic_cast(*Oasis::Add { logOf2, - logOf3 - }.Accept(simplifyVisitor).value()); - + logOf3 } + .Accept(simplifyVisitor) + .value()); + REQUIRE_THAT(logOf4Simplified.GetValue(), Catch::Matchers::WithinAbs(dynamic_cast(*logOf4.Accept(simplifyVisitor).value()).GetValue(), EPSILON)); REQUIRE_THAT(logOf6Simplified.GetValue(), Catch::Matchers::WithinAbs(dynamic_cast(*logOf6.Accept(simplifyVisitor).value()).GetValue(), EPSILON)); } @@ -184,11 +183,14 @@ TEST_CASE("Difference of logs", "[Log][Subtract]") auto logOf2Simplified = Oasis::Subtract { logOf4, logOf2 - }.Accept(simplifyVisitor).value(); + } + .Accept(simplifyVisitor) + .value(); auto logOf3Simplified = dynamic_cast(*Oasis::Subtract { logOf6, - logOf2 - }.Accept(simplifyVisitor).value()); + logOf2 } + .Accept(simplifyVisitor) + .value()); REQUIRE(logOf2Simplified->Equals(*(logOf2.Accept(simplifyVisitor).value()))); REQUIRE_THAT(logOf3Simplified.GetValue(), Catch::Matchers::WithinAbs(dynamic_cast(*(logOf3.Accept(simplifyVisitor).value())).GetValue(), EPSILON)); @@ -221,24 +223,29 @@ TEST_CASE("Change of Base", "[Log][Divide]") auto logBase2Simplified = Oasis::Divide { logOf4, logOf2 - }.Accept(simplifyVisitor).value(); + } + .Accept(simplifyVisitor) + .value(); auto logBase3Simplified = dynamic_cast(*Oasis::Divide { logOf6, - logOf3 - }.Accept(simplifyVisitor).value()); + logOf3 } + .Accept(simplifyVisitor) + .value()); REQUIRE(logBase2Simplified->Equals(two)); - REQUIRE_THAT(logBase3Simplified.GetValue(), Catch::Matchers::WithinAbs(dynamic_cast(*(logBase3.Accept(simplifyVisitor).value())).GetValue(), EPSILON)); //PROBLEM + REQUIRE_THAT(logBase3Simplified.GetValue(), Catch::Matchers::WithinAbs(dynamic_cast(*(logBase3.Accept(simplifyVisitor).value())).GetValue(), EPSILON)); // PROBLEM } -TEST_CASE("Log of Equal Base and Argument", "[Log][Expression]") { - Oasis::Log log {Oasis::Variable{"x"},Oasis::Variable {"x"}}; +TEST_CASE("Log of Equal Base and Argument", "[Log][Expression]") +{ + Oasis::Log log { Oasis::Variable { "x" }, Oasis::Variable { "x" } }; auto simplifiedLog = log.Accept(simplifyVisitor); - Oasis::Real expected {1}; + Oasis::Real expected { 1 }; REQUIRE(simplifiedLog.value()->Equals(expected)); } -TEST_CASE("Undefined", "[UNDEFINED][UNDEFINED]") { +TEST_CASE("Undefined", "[UNDEFINED][UNDEFINED]") +{ REQUIRE(!Oasis::Undefined().Equals(Oasis::Undefined())); REQUIRE(Oasis::Log(Oasis::Real(-1.0), Oasis::Real(5.0)).Accept(simplifyVisitor).value()->Is()); REQUIRE(Oasis::Log(Oasis::Real(5.0), Oasis::Real(-5.0)).Accept(simplifyVisitor).value()->Is()); @@ -247,29 +254,31 @@ TEST_CASE("Undefined", "[UNDEFINED][UNDEFINED]") { TEST_CASE("Integral of Natural Log", "[Integral][Log][Euler]") { - Oasis::Integral int1{Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"x"}}, Oasis::Variable{"x"}}; - Oasis::Integral int2{Oasis::Log{Oasis::EulerNumber{}, Oasis::Multiply{Oasis::Real{5}, Oasis::Variable{"x"}}}, Oasis::Variable{"x"}}; + Oasis::Integral int1 { Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "x" } }, Oasis::Variable { "x" } }; + Oasis::Integral int2 { Oasis::Log { Oasis::EulerNumber {}, Oasis::Multiply { Oasis::Real { 5 }, Oasis::Variable { "x" } } }, Oasis::Variable { "x" } }; auto simp1 = int1.Accept(simplifyVisitor).value(); auto simp2 = int2.Accept(simplifyVisitor).value(); // TODO: FIX - auto expected1 = Oasis::Add {Oasis::Multiply{Oasis::Subtract{Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"x"}}, Oasis::Real{1}} , Oasis::Variable{"x"} }, Oasis::Variable{"C"} }.Accept(simplifyVisitor).value(); - auto expected2 = Oasis::Add {Oasis::Multiply{Oasis::Subtract{Oasis::Log{Oasis::EulerNumber{}, Oasis::Multiply {Oasis::Real{5} ,Oasis::Variable{"x"}}}, Oasis::Real{1}} , Oasis::Variable{"x"} }, Oasis::Variable{"C"} }.Accept(simplifyVisitor).value(); + auto expected1 = Oasis::Add { Oasis::Multiply { Oasis::Subtract { Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "x" } }, Oasis::Real { 1 } }, Oasis::Variable { "x" } }, Oasis::Variable { "C" } }.Accept(simplifyVisitor).value(); + auto expected2 = Oasis::Add { Oasis::Multiply { Oasis::Subtract { Oasis::Log { Oasis::EulerNumber {}, Oasis::Multiply { Oasis::Real { 5 }, Oasis::Variable { "x" } } }, Oasis::Real { 1 } }, Oasis::Variable { "x" } }, Oasis::Variable { "C" } }.Accept(simplifyVisitor).value(); REQUIRE(simp1->Equals(*expected1)); REQUIRE(simp2->Equals(*expected2)); - } +} TEST_CASE("Integral of Non-Natural variable base Log", "[Integral][Log][Variable]") { - Oasis::Integral int1{Oasis::Log{Oasis::Variable{"y"}, Oasis::Variable{"x"}}, Oasis::Variable{"x"}}; - Oasis::Integral int2{Oasis::Log{Oasis::Variable{"y"}, Oasis::Multiply{Oasis::Real{5}, Oasis::Variable{"x"}}}, Oasis::Variable{"x"}}; - Oasis::Integral intEq{Oasis::Log{Oasis::Variable{"x"}, Oasis::Variable{"x"}}, Oasis::Variable{"x"}}; + Oasis::Integral int1 { Oasis::Log { Oasis::Variable { "y" }, Oasis::Variable { "x" } }, Oasis::Variable { "x" } }; + Oasis::Integral int2 { Oasis::Log { Oasis::Variable { "y" }, Oasis::Multiply { Oasis::Real { 5 }, Oasis::Variable { "x" } } }, Oasis::Variable { "x" } }; + Oasis::Integral intEq { Oasis::Log { Oasis::Variable { "x" }, Oasis::Variable { "x" } }, Oasis::Variable { "x" } }; - Oasis::Add eq1{Oasis::Divide{ Oasis::Multiply{Oasis::Variable{"x"}, Oasis::Subtract{Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"x"}}, Oasis::Real{1}}}, - Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"y"}}},Oasis::Variable{"C"}}; - Oasis::Add eq2{Oasis::Divide{ Oasis::Multiply{Oasis::Variable{"x"}, Oasis::Subtract{Oasis::Log{Oasis::EulerNumber{}, Oasis::Multiply{Oasis::Real{5}, Oasis::Variable{"x"}}},Oasis::Real{1}}}, - Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"y"}}},Oasis::Variable{"C"}}; + Oasis::Add eq1 { Oasis::Divide { Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Subtract { Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "x" } }, Oasis::Real { 1 } } }, + Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "y" } } }, + Oasis::Variable { "C" } }; + Oasis::Add eq2 { Oasis::Divide { Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Subtract { Oasis::Log { Oasis::EulerNumber {}, Oasis::Multiply { Oasis::Real { 5 }, Oasis::Variable { "x" } } }, Oasis::Real { 1 } } }, + Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "y" } } }, + Oasis::Variable { "C" } }; auto simp1 = int1.Accept(simplifyVisitor).value(); auto simp2 = int2.Accept(simplifyVisitor).value(); @@ -277,18 +286,20 @@ TEST_CASE("Integral of Non-Natural variable base Log", "[Integral][Log][Variable REQUIRE(simp1->Equals(*eq1.Accept(simplifyVisitor).value())); REQUIRE(simp2->Equals(*eq2.Accept(simplifyVisitor).value())); - REQUIRE(simpEq->Equals(Oasis::Add {Oasis::Variable{"x"}, Oasis::Variable{"C"} })); + REQUIRE(simpEq->Equals(Oasis::Add { Oasis::Variable { "x" }, Oasis::Variable { "C" } })); } TEST_CASE("Integral of Non-natural real base log", "[Integral][Log][Variable]") { - Oasis::Integral int1{Oasis::Log{Oasis::Real{10}, Oasis::Variable{"x"}}, Oasis::Variable{"x"}}; - Oasis::Integral int2{Oasis::Log{Oasis::Real{10}, Oasis::Multiply{Oasis::Real{5}, Oasis::Variable{"x"}}}, Oasis::Variable{"x"}}; - - Oasis::Add eq1{Oasis::Divide{ Oasis::Multiply{Oasis::Variable{"x"}, Oasis::Subtract{Oasis::Log{Oasis::EulerNumber{}, Oasis::Variable{"x"}}, Oasis::Real{1}}}, - Oasis::Log{Oasis::EulerNumber{}, Oasis::Real{10}}},Oasis::Variable{"C"}}; - Oasis::Add eq2{Oasis::Divide{ Oasis::Multiply{Oasis::Variable{"x"}, Oasis::Subtract{Oasis::Log{Oasis::EulerNumber{}, Oasis::Multiply{Oasis::Real{5}, Oasis::Variable{"x"}}}, Oasis::Real{1}}}, - Oasis::Log{Oasis::EulerNumber{}, Oasis::Real{10}}},Oasis::Variable{"C"}}; + Oasis::Integral int1 { Oasis::Log { Oasis::Real { 10 }, Oasis::Variable { "x" } }, Oasis::Variable { "x" } }; + Oasis::Integral int2 { Oasis::Log { Oasis::Real { 10 }, Oasis::Multiply { Oasis::Real { 5 }, Oasis::Variable { "x" } } }, Oasis::Variable { "x" } }; + + Oasis::Add eq1 { Oasis::Divide { Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Subtract { Oasis::Log { Oasis::EulerNumber {}, Oasis::Variable { "x" } }, Oasis::Real { 1 } } }, + Oasis::Log { Oasis::EulerNumber {}, Oasis::Real { 10 } } }, + Oasis::Variable { "C" } }; + Oasis::Add eq2 { Oasis::Divide { Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Subtract { Oasis::Log { Oasis::EulerNumber {}, Oasis::Multiply { Oasis::Real { 5 }, Oasis::Variable { "x" } } }, Oasis::Real { 1 } } }, + Oasis::Log { Oasis::EulerNumber {}, Oasis::Real { 10 } } }, + Oasis::Variable { "C" } }; auto simp1 = int1.Accept(simplifyVisitor).value(); auto simp2 = int2.Accept(simplifyVisitor).value(); diff --git a/tests/MagnitudeTests.cpp b/tests/MagnitudeTests.cpp index a8b0d6d6..23335b78 100644 --- a/tests/MagnitudeTests.cpp +++ b/tests/MagnitudeTests.cpp @@ -2,87 +2,87 @@ // Created by Andrew Nazareth on 6/28/24. // -#include "catch2/catch_test_macros.hpp" -#include "Oasis/Magnitude.hpp" -#include "Oasis/Real.hpp" -#include "Oasis/Multiply.hpp" -#include "Oasis/Imaginary.hpp" #include "Oasis/Add.hpp" -#include "Oasis/Subtract.hpp" +#include "Oasis/Imaginary.hpp" +#include "Oasis/Magnitude.hpp" #include "Oasis/Matrix.hpp" +#include "Oasis/Multiply.hpp" +#include "Oasis/Real.hpp" #include "Oasis/SimplifyVisitor.hpp" +#include "Oasis/Subtract.hpp" +#include "catch2/catch_test_macros.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Magnitude of Real", "[Magnitude][Real]") { - Oasis::Magnitude mag1{Oasis::Real{5.0}}; - Oasis::Magnitude mag2{Oasis::Real{-75.0}}; - Oasis::Magnitude mag3{Oasis::Add{Oasis::Real{5}, Oasis::Real{6}}}; - Oasis::Magnitude mag4{Oasis::Subtract{Oasis::Real{5}, Oasis::Real{6}}}; + Oasis::Magnitude mag1 { Oasis::Real { 5.0 } }; + Oasis::Magnitude mag2 { Oasis::Real { -75.0 } }; + Oasis::Magnitude mag3 { Oasis::Add { Oasis::Real { 5 }, Oasis::Real { 6 } } }; + Oasis::Magnitude mag4 { Oasis::Subtract { Oasis::Real { 5 }, Oasis::Real { 6 } } }; auto simp1 = mag1.Accept(simplifyVisitor).value(); auto simp2 = mag2.Accept(simplifyVisitor).value(); auto simp3 = mag3.Accept(simplifyVisitor).value(); auto simp4 = mag4.Accept(simplifyVisitor).value(); - REQUIRE(simp1->Equals(Oasis::Real{5.0})); - REQUIRE(simp2->Equals(Oasis::Real{75.0})); - REQUIRE(simp3->Equals(Oasis::Real{11.0})); - REQUIRE(simp4->Equals(Oasis::Real{1.0})); + REQUIRE(simp1->Equals(Oasis::Real { 5.0 })); + REQUIRE(simp2->Equals(Oasis::Real { 75.0 })); + REQUIRE(simp3->Equals(Oasis::Real { 11.0 })); + REQUIRE(simp4->Equals(Oasis::Real { 1.0 })); } TEST_CASE("Magnitude of Imaginary", "[Magnitude][Imaginary]") { - Oasis::Magnitude mag1{Oasis::Imaginary{}}; - Oasis::Magnitude mag2{Oasis::Multiply{Oasis::Real{5.0}, Oasis::Imaginary{}}}; - Oasis::Magnitude mag3{Oasis::Multiply{Oasis::Real{-5.0}, Oasis::Imaginary{}}}; + Oasis::Magnitude mag1 { Oasis::Imaginary {} }; + Oasis::Magnitude mag2 { Oasis::Multiply { Oasis::Real { 5.0 }, Oasis::Imaginary {} } }; + Oasis::Magnitude mag3 { Oasis::Multiply { Oasis::Real { -5.0 }, Oasis::Imaginary {} } }; auto simp1 = mag1.Accept(simplifyVisitor).value(); auto simp2 = mag2.Accept(simplifyVisitor).value(); auto simp3 = mag3.Accept(simplifyVisitor).value(); - REQUIRE(simp1->Equals(Oasis::Real{1.0})); - REQUIRE(simp2->Equals(Oasis::Real{5})); - REQUIRE(simp3->Equals(Oasis::Real{5})); + REQUIRE(simp1->Equals(Oasis::Real { 1.0 })); + REQUIRE(simp2->Equals(Oasis::Real { 5 })); + REQUIRE(simp3->Equals(Oasis::Real { 5 })); } TEST_CASE("Magnitude of Complex", "[Magnitude][Real][Imaginary]") { - Oasis::Magnitude mag1{Oasis::Add{Oasis::Real{5.0}, Oasis::Imaginary{}}}; - Oasis::Magnitude mag2{Oasis::Subtract{Oasis::Real{5.0}, Oasis::Imaginary{}}}; + Oasis::Magnitude mag1 { Oasis::Add { Oasis::Real { 5.0 }, Oasis::Imaginary {} } }; + Oasis::Magnitude mag2 { Oasis::Subtract { Oasis::Real { 5.0 }, Oasis::Imaginary {} } }; auto simp1 = mag1.Accept(simplifyVisitor).value(); auto simp2 = mag2.Accept(simplifyVisitor).value(); - REQUIRE(simp1->Equals(*Oasis::Exponent{Oasis::Real{26.0}, Oasis::Real{0.5}}.Accept(simplifyVisitor).value())); - REQUIRE(simp2->Equals(*Oasis::Exponent{Oasis::Real{26.0}, Oasis::Real{0.5}}.Accept(simplifyVisitor).value())); + REQUIRE(simp1->Equals(*Oasis::Exponent { Oasis::Real { 26.0 }, Oasis::Real { 0.5 } }.Accept(simplifyVisitor).value())); + REQUIRE(simp2->Equals(*Oasis::Exponent { Oasis::Real { 26.0 }, Oasis::Real { 0.5 } }.Accept(simplifyVisitor).value())); - Oasis::Magnitude mag3{Oasis::Add{Oasis::Real{5.0}, Oasis::Multiply{Oasis::Real{4.0}, Oasis::Imaginary{}}}}; - Oasis::Magnitude mag4{Oasis::Subtract{Oasis::Real{7.0}, Oasis::Multiply{Oasis::Real{20.0}, Oasis::Imaginary{}}}}; + Oasis::Magnitude mag3 { Oasis::Add { Oasis::Real { 5.0 }, Oasis::Multiply { Oasis::Real { 4.0 }, Oasis::Imaginary {} } } }; + Oasis::Magnitude mag4 { Oasis::Subtract { Oasis::Real { 7.0 }, Oasis::Multiply { Oasis::Real { 20.0 }, Oasis::Imaginary {} } } }; auto simp3 = mag3.Accept(simplifyVisitor).value(); auto simp4 = mag4.Accept(simplifyVisitor).value(); - REQUIRE(simp3->Equals(*Oasis::Exponent{Oasis::Real{41.0}, Oasis::Real{0.5}}.Accept(simplifyVisitor).value())); - REQUIRE(simp4->Equals(*Oasis::Exponent{Oasis::Real{449.0}, Oasis::Real{0.5}}.Accept(simplifyVisitor).value())); + REQUIRE(simp3->Equals(*Oasis::Exponent { Oasis::Real { 41.0 }, Oasis::Real { 0.5 } }.Accept(simplifyVisitor).value())); + REQUIRE(simp4->Equals(*Oasis::Exponent { Oasis::Real { 449.0 }, Oasis::Real { 0.5 } }.Accept(simplifyVisitor).value())); } TEST_CASE("Magnitude of Vector", "[Magnitude][Matrix1D]") { - std::vector vals = {5,6,7,8}; - Oasis::Magnitude mag1{Oasis::Matrix{4, 1, vals}}; - Oasis::Magnitude mag2{Oasis::Matrix{1, 4, vals}}; - auto expected = Oasis::Exponent{Oasis::Real{174}, Oasis::Real{0.5}}.Accept(simplifyVisitor).value(); + std::vector vals = { 5, 6, 7, 8 }; + Oasis::Magnitude mag1 { Oasis::Matrix { 4, 1, vals } }; + Oasis::Magnitude mag2 { Oasis::Matrix { 1, 4, vals } }; + auto expected = Oasis::Exponent { Oasis::Real { 174 }, Oasis::Real { 0.5 } }.Accept(simplifyVisitor).value(); REQUIRE((mag1.Accept(simplifyVisitor).value())->Equals(*expected)); REQUIRE((mag2.Accept(simplifyVisitor).value())->Equals(*expected)); } TEST_CASE("Magnitude of Matrix", "[Magnitude][MatrixXXD]") { - std::vector vals = {5,6,7,8}; - Oasis::Magnitude mag1{Oasis::Matrix{2, 2, vals}}; - auto expected = Oasis::Exponent{Oasis::Real{174}, Oasis::Real{0.5}}.Accept(simplifyVisitor).value(); + std::vector vals = { 5, 6, 7, 8 }; + Oasis::Magnitude mag1 { Oasis::Matrix { 2, 2, vals } }; + auto expected = Oasis::Exponent { Oasis::Real { 174 }, Oasis::Real { 0.5 } }.Accept(simplifyVisitor).value(); auto actual = mag1.Accept(simplifyVisitor).value(); REQUIRE(actual->Equals(*expected)); } \ No newline at end of file diff --git a/tests/MatrixTests.cpp b/tests/MatrixTests.cpp index ade15cb0..1cbe2a78 100644 --- a/tests/MatrixTests.cpp +++ b/tests/MatrixTests.cpp @@ -2,22 +2,22 @@ // Created by Andrew Nazareth on 5/24/24. // -#include "catch2/catch_test_macros.hpp" -#include -#include "Oasis/Matrix.hpp" #include "Oasis/Add.hpp" -#include "Oasis/Subtract.hpp" +#include "Oasis/Matrix.hpp" #include "Oasis/Multiply.hpp" #include "Oasis/RecursiveCast.hpp" #include "Oasis/SimplifyVisitor.hpp" +#include "Oasis/Subtract.hpp" +#include "catch2/catch_test_macros.hpp" +#include #define EPSILON 10E-6 -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Create Empty Matrix", "[Matrix][Create][Empty]") { - Oasis::Matrix a = {3,4}; + Oasis::Matrix a = { 3, 4 }; REQUIRE(a.GetCols() == 4); REQUIRE(a.GetRows() == 3); @@ -25,20 +25,20 @@ TEST_CASE("Create Empty Matrix", "[Matrix][Create][Empty]") TEST_CASE("Create Matrix From MatrixXXD", "[Matrix][Create][MatrixXXD]") { - Oasis::MatrixXXD a{2,2}; - a(0,0) = 1; - a(0,1) = 2; - a(1,0) = 3; - a(1,1) = 4; + Oasis::MatrixXXD a { 2, 2 }; + a(0, 0) = 1; + a(0, 1) = 2; + a(1, 0) = 3; + a(1, 1) = 4; - Oasis::Matrix mat{a}; + Oasis::Matrix mat { a }; - Oasis::Matrix mat2{Oasis::MatrixXXD{{1,2},{3,4}}}; + Oasis::Matrix mat2 { Oasis::MatrixXXD { { 1, 2 }, { 3, 4 } } }; - Oasis::MatrixXXD b{2,2}; + Oasis::MatrixXXD b { 2, 2 }; b << 1, 2, 3, 4; - Oasis::Matrix mat3{b}; + Oasis::Matrix mat3 { b }; REQUIRE(mat.GetMatrix() == a); REQUIRE(mat2.Equals(mat)); @@ -47,11 +47,11 @@ TEST_CASE("Create Matrix From MatrixXXD", "[Matrix][Create][MatrixXXD]") TEST_CASE("Create Matrix from Vector", "[Matrix][Create][Vector]") { - std::vector matrix = {1,2,3,4}; - Oasis::Matrix even{2,2,matrix}; - Oasis::Matrix less{1,2,matrix}; - Oasis::Matrix more{2,3,matrix}; - Oasis::Matrix less2{2,1,matrix}; + std::vector matrix = { 1, 2, 3, 4 }; + Oasis::Matrix even { 2, 2, matrix }; + Oasis::Matrix less { 1, 2, matrix }; + Oasis::Matrix more { 2, 3, matrix }; + Oasis::Matrix less2 { 2, 1, matrix }; INFO("Even:"); INFO(even.GetMatrix()); @@ -65,92 +65,92 @@ TEST_CASE("Create Matrix from Vector", "[Matrix][Create][Vector]") TEST_CASE("Add Matrices", "[Matrix][Add]") { - Oasis::Matrix mat1{Oasis::MatrixXXD{{1,2}, - {3,4}}}; - Oasis::Matrix mat2{Oasis::MatrixXXD{{8,7}, - {6,5}}}; + Oasis::Matrix mat1 { Oasis::MatrixXXD { { 1, 2 }, + { 3, 4 } } }; + Oasis::Matrix mat2 { Oasis::MatrixXXD { { 8, 7 }, + { 6, 5 } } }; - auto result = Oasis::Add{mat1, mat2}.Accept(simplifyVisitor).value(); + auto result = Oasis::Add { mat1, mat2 }.Accept(simplifyVisitor).value(); auto spec = Oasis::RecursiveCast(*result); REQUIRE(spec != nullptr); - REQUIRE(spec->Equals(Oasis::Matrix{Oasis::MatrixXXD{{9,9},{9,9}}})); + REQUIRE(spec->Equals(Oasis::Matrix { Oasis::MatrixXXD { { 9, 9 }, { 9, 9 } } })); // std::cout<GetMatrix()<{mat2, mat1}.Accept(simplifyVisitor).value(); + auto result = Oasis::Subtract { mat2, mat1 }.Accept(simplifyVisitor).value(); auto spec = Oasis::RecursiveCast(*result); REQUIRE(spec != nullptr); - REQUIRE(spec->Equals(Oasis::Matrix{Oasis::MatrixXXD{{4,4},{4,4}}})); + REQUIRE(spec->Equals(Oasis::Matrix { Oasis::MatrixXXD { { 4, 4 }, { 4, 4 } } })); } TEST_CASE("Multiply Matrix and Real", "[Matrix][Real][Multiply]") { - Oasis::Real a {5.0}; - Oasis::Matrix mat1{Oasis::MatrixXXD{{1,2}, - {3,4}}}; + Oasis::Real a { 5.0 }; + Oasis::Matrix mat1 { Oasis::MatrixXXD { { 1, 2 }, + { 3, 4 } } }; - auto result1 = Oasis::Multiply{a, mat1}.Accept(simplifyVisitor).value(); - auto result2 = Oasis::Multiply{mat1, a}.Accept(simplifyVisitor).value(); + auto result1 = Oasis::Multiply { a, mat1 }.Accept(simplifyVisitor).value(); + auto result2 = Oasis::Multiply { mat1, a }.Accept(simplifyVisitor).value(); auto spec1 = Oasis::RecursiveCast(*result1); auto spec2 = Oasis::RecursiveCast(*result2); REQUIRE(spec1 != nullptr); REQUIRE(spec2 != nullptr); - REQUIRE(spec1->Equals(Oasis::Matrix{Oasis::MatrixXXD{{5.0, 10.0},{15.0, 20.0}}})); - REQUIRE(spec2->Equals(Oasis::Matrix{Oasis::MatrixXXD{{5.0, 10.0},{15.0, 20.0}}})); + REQUIRE(spec1->Equals(Oasis::Matrix { Oasis::MatrixXXD { { 5.0, 10.0 }, { 15.0, 20.0 } } })); + REQUIRE(spec2->Equals(Oasis::Matrix { Oasis::MatrixXXD { { 5.0, 10.0 }, { 15.0, 20.0 } } })); } TEST_CASE("Create Identity Matrix", "[Matrix][Identity]") { - Oasis::MatrixXXD mat(3,3); - Oasis::Matrix i{mat}; + Oasis::MatrixXXD mat(3, 3); + Oasis::Matrix i { mat }; Oasis::Matrix identity = *(Oasis::RecursiveCast(*i.Identity())); - mat << 1,0,0, - 0,1,0, - 0,0,1; + mat << 1, 0, 0, + 0, 1, 0, + 0, 0, 1; REQUIRE(identity.GetMatrix() == mat); } TEST_CASE("Multiply Matrices, same dimensions", "[Matrix][Multiply]") { - Oasis::Matrix mat1{Oasis::MatrixXXD{{5,6},{7,8}}}; - Oasis::Matrix mat2{Oasis::MatrixXXD{{1,2},{3,4}}}; - Oasis::Matrix expected{Oasis::MatrixXXD{{23,34},{31,46}}}; - auto result = Oasis::Multiply{mat1, mat2}.Accept(simplifyVisitor).value(); + Oasis::Matrix mat1 { Oasis::MatrixXXD { { 5, 6 }, { 7, 8 } } }; + Oasis::Matrix mat2 { Oasis::MatrixXXD { { 1, 2 }, { 3, 4 } } }; + Oasis::Matrix expected { Oasis::MatrixXXD { { 23, 34 }, { 31, 46 } } }; + auto result = Oasis::Multiply { mat1, mat2 }.Accept(simplifyVisitor).value(); REQUIRE(result->Equals(expected)); } TEST_CASE("Multiply Matrices, different dimensions", "[Matrix][Multiply]") { - Oasis::Matrix mat1{Oasis::MatrixXXD{{1,2},{3,4}}}; - Oasis::Matrix mat2{Oasis::MatrixXXD{{1,2},{3,4},{5,6}}}; - Oasis::Matrix mat3{Oasis::MatrixXXD{{1,2,3},{4,5,6}}}; - - Oasis::Multiply expected12{mat1, mat2}; - Oasis::Matrix expected21{Oasis::MatrixXXD{{7,10},{15,22},{23,34}}}; - Oasis::Matrix expected13{Oasis::MatrixXXD{{9,12,15},{19,26,33}}}; - Oasis::Multiply expected31{mat3, mat1}; - Oasis::Matrix expected23{Oasis::MatrixXXD{{9,12,15},{19,26,33},{29,40,51}}}; - Oasis::Matrix expected32{Oasis::MatrixXXD{{22,28},{49,64}}}; - - auto res12 = Oasis::Multiply{mat1, mat2}.Accept(simplifyVisitor).value(); - auto res21 = Oasis::Multiply{mat2, mat1}.Accept(simplifyVisitor).value(); - auto res13 = Oasis::Multiply{mat1, mat3}.Accept(simplifyVisitor).value(); - auto res31 = Oasis::Multiply{mat3, mat1}.Accept(simplifyVisitor).value(); - auto res23 = Oasis::Multiply{mat2, mat3}.Accept(simplifyVisitor).value(); - auto res32 = Oasis::Multiply{mat3, mat2}.Accept(simplifyVisitor).value(); + Oasis::Matrix mat1 { Oasis::MatrixXXD { { 1, 2 }, { 3, 4 } } }; + Oasis::Matrix mat2 { Oasis::MatrixXXD { { 1, 2 }, { 3, 4 }, { 5, 6 } } }; + Oasis::Matrix mat3 { Oasis::MatrixXXD { { 1, 2, 3 }, { 4, 5, 6 } } }; + + Oasis::Multiply expected12 { mat1, mat2 }; + Oasis::Matrix expected21 { Oasis::MatrixXXD { { 7, 10 }, { 15, 22 }, { 23, 34 } } }; + Oasis::Matrix expected13 { Oasis::MatrixXXD { { 9, 12, 15 }, { 19, 26, 33 } } }; + Oasis::Multiply expected31 { mat3, mat1 }; + Oasis::Matrix expected23 { Oasis::MatrixXXD { { 9, 12, 15 }, { 19, 26, 33 }, { 29, 40, 51 } } }; + Oasis::Matrix expected32 { Oasis::MatrixXXD { { 22, 28 }, { 49, 64 } } }; + + auto res12 = Oasis::Multiply { mat1, mat2 }.Accept(simplifyVisitor).value(); + auto res21 = Oasis::Multiply { mat2, mat1 }.Accept(simplifyVisitor).value(); + auto res13 = Oasis::Multiply { mat1, mat3 }.Accept(simplifyVisitor).value(); + auto res31 = Oasis::Multiply { mat3, mat1 }.Accept(simplifyVisitor).value(); + auto res23 = Oasis::Multiply { mat2, mat3 }.Accept(simplifyVisitor).value(); + auto res32 = Oasis::Multiply { mat3, mat2 }.Accept(simplifyVisitor).value(); REQUIRE(res12->Equals(expected12)); REQUIRE(res21->Equals(expected21)); diff --git a/tests/MultiplyTests.cpp b/tests/MultiplyTests.cpp index 355ddffc..8b4666cd 100644 --- a/tests/MultiplyTests.cpp +++ b/tests/MultiplyTests.cpp @@ -2,8 +2,8 @@ // Created by Matthew McCall on 8/10/23. // -#include "catch2/catch_test_macros.hpp" #include "Common.hpp" +#include "catch2/catch_test_macros.hpp" #include "Oasis/Add.hpp" #include "Oasis/Exponent.hpp" @@ -14,7 +14,7 @@ #include "Oasis/RecursiveCast.hpp" #include -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Multiplication", "[Multiply]") { @@ -100,14 +100,14 @@ TEST_CASE("Multiply Associativity", "[Multiply][Associativity]") Oasis::Real { 5.0 } }, Oasis::Real { 3.0 } }, Oasis::Variable { "y" } } - .Equals(*simplified1)); + .Equals(*simplified1)); } TEST_CASE("Multiply Operator Overload", "[Multiply][Operator Overload]") { const std::unique_ptr a = std::make_unique(1.0); const std::unique_ptr b = std::make_unique(2.0); - const auto sum = a*b; + const auto sum = a * b; auto realSum = Oasis::RecursiveCast(*sum); REQUIRE(realSum != nullptr); @@ -124,7 +124,7 @@ TEST_CASE("Variadic Multiply Constructor", "[Multiply]") Oasis::Add<> { Oasis::Real { 5.0 }, Oasis::Real { 6.0 }, - Oasis::Real { 7.0 }} + Oasis::Real { 7.0 } } }; const Oasis::Real expected { 432.0 }; @@ -135,15 +135,15 @@ TEST_CASE("Variadic Multiply Constructor", "[Multiply]") TEST_CASE("Multiplying Fractions", "[Multiply]") { - const Oasis::Multiply,Oasis::Divide<>> multiply { - Oasis::Divide<> { Oasis::Multiply{ Oasis::Variable{ "a"}, - Oasis::Variable{"b"} }, - Oasis::Multiply{ Oasis::Variable{ "c"}, - Oasis::Real{4.0} } }, - Oasis::Divide<> { Oasis::Multiply{ Oasis::Variable{ "c"}, - Oasis::Real{12.0} }, - Oasis::Multiply{ Oasis::Variable{ "b"}, - Oasis::Variable{"a"} } } + const Oasis::Multiply, Oasis::Divide<>> multiply { + Oasis::Divide<> { Oasis::Multiply { Oasis::Variable { "a" }, + Oasis::Variable { "b" } }, + Oasis::Multiply { Oasis::Variable { "c" }, + Oasis::Real { 4.0 } } }, + Oasis::Divide<> { Oasis::Multiply { Oasis::Variable { "c" }, + Oasis::Real { 12.0 } }, + Oasis::Multiply { Oasis::Variable { "b" }, + Oasis::Variable { "a" } } } }; const Oasis::Real expected { 3.0 }; @@ -156,25 +156,25 @@ TEST_CASE("Multiplying Linear Expressions", "[Multiply]") { // 2*(4x-5) Oasis::Multiply multiply { - Oasis::Real{2}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{4}, - Oasis::Variable{"x"}}, - Oasis::Real{-5}} + Oasis::Real { 2 }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { 4 }, + Oasis::Variable { "x" } }, + Oasis::Real { -5 } } }; - Oasis::SimplifyOpts opts = {.distributivePolicy = Oasis::SimplifyOpts::DistributivePolicy::PREFER}; - Oasis::SimplifyVisitor distributiveSimplifyVisitor { opts}; + Oasis::SimplifyOpts opts = { .distributivePolicy = Oasis::SimplifyOpts::DistributivePolicy::PREFER }; + Oasis::SimplifyVisitor distributiveSimplifyVisitor { opts }; const auto multiply_simplified = multiply.Accept(distributiveSimplifyVisitor).value(); // 8x-10 const Oasis::Add expected { - Oasis::Multiply{ - Oasis::Real{8}, - Oasis::Variable{"x"}}, - Oasis::Real{-10} + Oasis::Multiply { + Oasis::Real { 8 }, + Oasis::Variable { "x" } }, + Oasis::Real { -10 } }; OASIS_CAPTURE_WITH_SERIALIZER((*multiply_simplified)); @@ -186,33 +186,32 @@ TEST_CASE("Multiplying Quadratics", "[Multiply]") { // 2*(3x^2+4x-5) Oasis::Multiply polynom { - Oasis::Real{2}, + Oasis::Real { 2 }, Oasis::Add { - Oasis::Multiply{ - Oasis::Real{3}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{4}, - Oasis::Variable{"x"}}, - Oasis::Real{-5}} - } + Oasis::Multiply { + Oasis::Real { 3 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { 4 }, + Oasis::Variable { "x" } }, + Oasis::Real { -5 } } } }; - Oasis::SimplifyOpts opts = {.distributivePolicy = Oasis::SimplifyOpts::DistributivePolicy::PREFER}; - Oasis::SimplifyVisitor distributiveSimplifyVisitor { opts}; + Oasis::SimplifyOpts opts = { .distributivePolicy = Oasis::SimplifyOpts::DistributivePolicy::PREFER }; + Oasis::SimplifyVisitor distributiveSimplifyVisitor { opts }; const auto simplified = polynom.Accept(distributiveSimplifyVisitor).value(); // 6x^2+8x-10 const Oasis::Add expected { - Oasis::Multiply{ - Oasis::Real{6}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{8}, - Oasis::Variable{"x"}}, - Oasis::Real{-10}} + Oasis::Multiply { + Oasis::Real { 6 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { 8 }, + Oasis::Variable { "x" } }, + Oasis::Real { -10 } } }; auto expected_simpl = expected.Accept(simplifyVisitor).value(); diff --git a/tests/NegateTests.cpp b/tests/NegateTests.cpp index 90219fa7..47c47ba8 100644 --- a/tests/NegateTests.cpp +++ b/tests/NegateTests.cpp @@ -5,14 +5,14 @@ #include "Common.hpp" #include "catch2/catch_test_macros.hpp" -#include -#include "Oasis/Subtract.hpp" #include "Oasis/Add.hpp" -#include "Oasis/Variable.hpp" #include "Oasis/Real.hpp" #include "Oasis/SimplifyVisitor.hpp" +#include "Oasis/Subtract.hpp" +#include "Oasis/Variable.hpp" +#include -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Negate", "[Negate]") { @@ -31,30 +31,30 @@ TEST_CASE("Quadratic Negation", "[Negate]") // -(3x^2+4x-5) Oasis::Negate polynom_negated { Oasis::Add { - Oasis::Multiply{ - Oasis::Real{3}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{4}, - Oasis::Variable{"x"}}, - Oasis::Real{-5}} - } + Oasis::Multiply { + Oasis::Real { 3 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { 4 }, + Oasis::Variable { "x" } }, + Oasis::Real { -5 } } } }; const auto polynom_negated_simpl = polynom_negated.Accept(simplifyVisitor).value(); // -3x^2-4x+5 const auto expected = Oasis::Add { - Oasis::Multiply{ - Oasis::Real{-3}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{-4}, - Oasis::Variable{"x"}}, - Oasis::Real{5}} - }.Accept(simplifyVisitor).value(); + Oasis::Multiply { + Oasis::Real { -3 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { -4 }, + Oasis::Variable { "x" } }, + Oasis::Real { 5 } } + }.Accept(simplifyVisitor) + .value(); OASIS_CAPTURE_WITH_SERIALIZER(*polynom_negated_simpl); OASIS_CAPTURE_WITH_SERIALIZER(*expected); diff --git a/tests/SubtractTests.cpp b/tests/SubtractTests.cpp index 3370eb4c..d462b213 100644 --- a/tests/SubtractTests.cpp +++ b/tests/SubtractTests.cpp @@ -16,7 +16,7 @@ #include "Oasis/Subtract.hpp" #include "Oasis/Variable.hpp" -inline Oasis::SimplifyVisitor simplifyVisitor{}; +inline Oasis::SimplifyVisitor simplifyVisitor {}; TEST_CASE("Subtraction", "[Subtract]") { @@ -69,24 +69,24 @@ TEST_CASE("Subtract Operator Overload", "[Subtract][Operator Overload]") const std::unique_ptr a = std::make_unique(1.0); const std::unique_ptr b = std::make_unique(2.0); - const auto sum = a-b; + const auto sum = a - b; auto realSum = Oasis::RecursiveCast(*sum); REQUIRE(realSum != nullptr); REQUIRE(realSum->GetValue() == -1.0); - } -TEST_CASE("Simplify Equation with subtraction", "[Subtract]") { - Oasis::Add add1{ // 4x - 7y + -5 - Oasis::Subtract{ - Oasis::Multiply{ - Oasis::Real{4.0}, - Oasis::Variable{"x"}}, - Oasis::Multiply{ - Oasis::Real{7.0}, - Oasis::Variable{"y"}}}, - Oasis::Real{-5.0} +TEST_CASE("Simplify Equation with subtraction", "[Subtract]") +{ + Oasis::Add add1 { // 4x - 7y + -5 + Oasis::Subtract { + Oasis::Multiply { + Oasis::Real { 4.0 }, + Oasis::Variable { "x" } }, + Oasis::Multiply { + Oasis::Real { 7.0 }, + Oasis::Variable { "y" } } }, + Oasis::Real { -5.0 } }; auto simplified = add1.Accept(simplifyVisitor).value(); @@ -95,55 +95,56 @@ TEST_CASE("Simplify Equation with subtraction", "[Subtract]") { TEST_CASE("Polynomial Subtraction", "[Subtract]") { Oasis::Add polynom1 { // 6x^2+3x-15 - Oasis::Multiply{ - Oasis::Real{6}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{3}, - Oasis::Variable{"x"}}, - Oasis::Real{-15}} + Oasis::Multiply { + Oasis::Real { 6 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { 3 }, + Oasis::Variable { "x" } }, + Oasis::Real { -15 } } }; Oasis::Add polynom2 { // 3x^2+4x-5 - Oasis::Multiply{ - Oasis::Real{3}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{4}, - Oasis::Variable{"x"}}, - Oasis::Real{-5}} + Oasis::Multiply { + Oasis::Real { 3 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { 4 }, + Oasis::Variable { "x" } }, + Oasis::Real { -5 } } }; Oasis::Add polynom2_negated { // -3x^2-4x+5 - Oasis::Multiply{ - Oasis::Real{-3}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{-4}, - Oasis::Variable{"x"}}, - Oasis::Real{5}} + Oasis::Multiply { + Oasis::Real { -3 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { -4 }, + Oasis::Variable { "x" } }, + Oasis::Real { 5 } } }; Oasis::Add expected { // 3x^2-x-10 - Oasis::Multiply{ - Oasis::Real{3}, - Oasis::Multiply{ Oasis::Variable{"x"}, Oasis::Variable{"x"}}}, - Oasis::Add{ - Oasis::Multiply{ - Oasis::Real{-1}, - Oasis::Variable{"x"}}, - Oasis::Real{-10}} + Oasis::Multiply { + Oasis::Real { 3 }, + Oasis::Multiply { Oasis::Variable { "x" }, Oasis::Variable { "x" } } }, + Oasis::Add { + Oasis::Multiply { + Oasis::Real { -1 }, + Oasis::Variable { "x" } }, + Oasis::Real { -10 } } }; auto expected_simplified = expected.Accept(simplifyVisitor).value(); - auto subtracted = Oasis::Subtract{ + auto subtracted = Oasis::Subtract { polynom1, polynom2 - }.Accept(simplifyVisitor).value(); - + } + .Accept(simplifyVisitor) + .value(); OASIS_CAPTURE_WITH_SERIALIZER(*subtracted); OASIS_CAPTURE_WITH_SERIALIZER(*expected_simplified); diff --git a/tests/UnaryExpressionTests.cpp b/tests/UnaryExpressionTests.cpp index 8c5fa746..2ffc8e5a 100644 --- a/tests/UnaryExpressionTests.cpp +++ b/tests/UnaryExpressionTests.cpp @@ -15,7 +15,7 @@ TEST_CASE("Substitute Unary", "[Substitute]") Oasis::Multiply { Oasis::Real { 2.0 }, Oasis::Negate { Oasis::Variable { "x" } } }, - Oasis::Multiply{ + Oasis::Multiply { Oasis::Real { 3.0 }, Oasis::Variable { "x" } } }; // -2x+3x