From bf022c0563cf4bd8757d8e23ea53733ea2d8b2e0 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 24 Oct 2025 18:09:32 -0400 Subject: [PATCH 01/16] Replaced uses of Simplify() with SimplifyVisitor{}. This is to leverage the visitor pattern and the ability to pass states with one object rather than passing a series of individual states through the simplify chain. An example of this would be degrees vs radians for trig functions. With the new visitor pattern, we can pass that option to all nodes that need it without passing additional parameters to each class's Simplify() function. --- include/CMakeLists.txt | 2 + include/Oasis/Add.hpp | 1 + include/Oasis/BinaryExpression.hpp | 12 +- include/Oasis/Derivative.hpp | 1 + include/Oasis/Divide.hpp | 1 + include/Oasis/Exponent.hpp | 1 + include/Oasis/Expression.hpp | 5 +- include/Oasis/Integral.hpp | 3 + include/Oasis/Log.hpp | 1 + include/Oasis/Magnitude.hpp | 11 +- include/Oasis/Multiply.hpp | 1 + include/Oasis/Negate.hpp | 5 +- include/Oasis/SimplifyVisitor.hpp | 57 + include/Oasis/Sine.hpp | 42 + include/Oasis/Subtract.hpp | 1 + include/Oasis/UnaryExpression.hpp | 6 +- include/Oasis/Visit.hpp | 10 +- io/include/Oasis/InFixSerializer.hpp | 1 + io/include/Oasis/MathMLSerializer.hpp | 2 +- io/include/Oasis/TeXSerializer.hpp | 1 + io/src/InFixSerializer.cpp | 8 + io/src/MathMLSerializer.cpp | 41 +- io/src/TeXSerializer.cpp | 8 + src/CMakeLists.txt | 4 +- src/Linear.cpp | 6 +- src/Log.cpp | 8 +- src/SimplifyVisitor.cpp | 1487 +++++++++++++++++++++++++ src/Sine.cpp | 24 + tests/AddTests.cpp | 19 +- tests/BinaryExpressionTests.cpp | 5 +- tests/DifferentiateTests.cpp | 91 +- tests/DivideTests.cpp | 23 +- tests/ExponentTests.cpp | 69 +- tests/IntegrateTests.cpp | 23 +- tests/LogTests.cpp | 71 +- tests/MagnitudeTests.cpp | 44 +- tests/MatrixTests.cpp | 25 +- tests/MultiplyTests.cpp | 20 +- tests/NegateTests.cpp | 5 +- tests/SubtractTests.cpp | 11 +- tests/UnaryExpressionTests.cpp | 2 +- 41 files changed, 1937 insertions(+), 221 deletions(-) create mode 100644 include/Oasis/SimplifyVisitor.hpp create mode 100644 include/Oasis/Sine.hpp create mode 100644 src/SimplifyVisitor.cpp create mode 100644 src/Sine.cpp diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index b41736c7..faa95afa 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -20,6 +20,8 @@ set(Oasis_HEADERS Oasis/Pi.hpp Oasis/Real.hpp Oasis/RecursiveCast.hpp + Oasis/SimplifyVisitor.hpp + Oasis/Sine.hpp Oasis/Subtract.hpp Oasis/UnaryExpression.hpp Oasis/Undefined.hpp diff --git a/include/Oasis/Add.hpp b/include/Oasis/Add.hpp index b61e6d7f..0bd33e9c 100644 --- a/include/Oasis/Add.hpp +++ b/include/Oasis/Add.hpp @@ -20,6 +20,7 @@ class Add< public: using BinaryExpression::BinaryExpression; + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; diff --git a/include/Oasis/BinaryExpression.hpp b/include/Oasis/BinaryExpression.hpp index 30af5a1b..b06216be 100644 --- a/include/Oasis/BinaryExpression.hpp +++ b/include/Oasis/BinaryExpression.hpp @@ -13,6 +13,7 @@ #include "Expression.hpp" #include "RecursiveCast.hpp" #include "Visit.hpp" +#include "Oasis/SimplifyVisitor.hpp" namespace Oasis { /** @@ -361,11 +362,18 @@ class BinaryExpression : public Expression { auto Substitute(const Expression& var, const Expression& val) -> std::unique_ptr override { + // TODO: FIX WITH VISITOR? std::unique_ptr left = ((GetMostSigOp()).Copy())->Substitute(var, val); std::unique_ptr right = ((GetLeastSigOp().Copy())->Substitute(var, val)); DerivedT comb = DerivedT { *left, *right }; - auto ret = comb.Simplify(); - return ret; + + Oasis::SimplifyVisitor simplifyVisitor{}; + auto simplified = comb.Accept(simplifyVisitor); + if (!simplified) + { + return comb.Generalize(); + } + return std::move(simplified.value()); } /** * Swaps the operands of this expression. diff --git a/include/Oasis/Derivative.hpp b/include/Oasis/Derivative.hpp index bab38b2c..0fe86d98 100644 --- a/include/Oasis/Derivative.hpp +++ b/include/Oasis/Derivative.hpp @@ -21,6 +21,7 @@ class Derivative : public BinaryExpression { Derivative(const Expression& Exp, const Expression& Var); + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr override; diff --git a/include/Oasis/Divide.hpp b/include/Oasis/Divide.hpp index 19a412ab..fe51fa11 100644 --- a/include/Oasis/Divide.hpp +++ b/include/Oasis/Divide.hpp @@ -21,6 +21,7 @@ class Divide : public BinaryExpression { Divide(const Expression& dividend, const Expression& divisor); + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; diff --git a/include/Oasis/Exponent.hpp b/include/Oasis/Exponent.hpp index bf9a3d1c..b65a7dc2 100644 --- a/include/Oasis/Exponent.hpp +++ b/include/Oasis/Exponent.hpp @@ -22,6 +22,7 @@ class Exponent : public BinaryExpression { Exponent(const Expression& base, const Expression& power); + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; diff --git a/include/Oasis/Expression.hpp b/include/Oasis/Expression.hpp index 2053875b..c41bf97c 100644 --- a/include/Oasis/Expression.hpp +++ b/include/Oasis/Expression.hpp @@ -38,7 +38,8 @@ enum class ExpressionType { Matrix, Pi, EulerNumber, - Magnitude + Magnitude, + Sine }; /** @@ -210,7 +211,7 @@ template auto Expression::Accept(T& visitor) const -> typename T::RetT { try { - return boost::any_cast(this->AcceptInternal(visitor)); + return boost::any_cast(this->AcceptInternal(static_cast(visitor))); } catch (boost::bad_any_cast& e) { return std::unexpected { e.what() }; } diff --git a/include/Oasis/Integral.hpp b/include/Oasis/Integral.hpp index 5241648a..34f3c3ec 100644 --- a/include/Oasis/Integral.hpp +++ b/include/Oasis/Integral.hpp @@ -23,7 +23,10 @@ class Integral : public BinaryExpression { Integral(const Expression& integrand, const Expression& differential); + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; + + [[deprecated]] [[nodiscard]] auto Simplify(const Expression& upper, const Expression& lower) const -> std::unique_ptr /* final */; EXPRESSION_TYPE(Integral) diff --git a/include/Oasis/Log.hpp b/include/Oasis/Log.hpp index 7c1a1f7d..32b2d266 100644 --- a/include/Oasis/Log.hpp +++ b/include/Oasis/Log.hpp @@ -22,6 +22,7 @@ class Log : public BinaryExpression { Log(const Expression& base, const Expression& argument); + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Integrate(const Expression& integrationVariable) const -> std::unique_ptr final; diff --git a/include/Oasis/Magnitude.hpp b/include/Oasis/Magnitude.hpp index df542a7d..0f69d7ae 100644 --- a/include/Oasis/Magnitude.hpp +++ b/include/Oasis/Magnitude.hpp @@ -16,6 +16,7 @@ #include "Real.hpp" #include "RecursiveCast.hpp" #include "UnaryExpression.hpp" +#include "Oasis/SimplifyVisitor.hpp" namespace Oasis { @@ -24,7 +25,7 @@ namespace Oasis { * @tparam OperandT Type of child operand * This represents magnitude/absolute value */ -template +template class Magnitude final : public UnaryExpression { public: Magnitude() = default; @@ -38,6 +39,7 @@ class Magnitude final : public UnaryExpression { { } + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr override { auto simpOp = this->GetOperand().Simplify(); @@ -79,12 +81,12 @@ 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 - } - .Simplify(); + }.Generalize(); } [[nodiscard]] auto Integrate(const Expression& integrationVar) const -> std::unique_ptr override @@ -93,8 +95,7 @@ class Magnitude final : public UnaryExpression { const std::unique_ptr operandDerivative = this->GetOperand().Integrate(integrationVar); return Magnitude { *operandDerivative - } - .Simplify(); + }.Generalize(); } EXPRESSION_TYPE(Magnitude) diff --git a/include/Oasis/Multiply.hpp b/include/Oasis/Multiply.hpp index 14546868..ebc4b7d5 100644 --- a/include/Oasis/Multiply.hpp +++ b/include/Oasis/Multiply.hpp @@ -19,6 +19,7 @@ class Multiply : public BinaryExpression { public: using BinaryExpression::BinaryExpression; + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; diff --git a/include/Oasis/Negate.hpp b/include/Oasis/Negate.hpp index e9c715ae..555927ac 100644 --- a/include/Oasis/Negate.hpp +++ b/include/Oasis/Negate.hpp @@ -10,7 +10,7 @@ namespace Oasis { -template +template class Negate final : public UnaryExpression { public: Negate() = default; @@ -24,6 +24,7 @@ class Negate final : public UnaryExpression { { } + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr override { return Multiply { @@ -39,7 +40,7 @@ class Negate final : public UnaryExpression { return Negate { *operandDerivative } - .Simplify(); + .Generalize(); // TODO: FIX WITH VISITOR } EXPRESSION_TYPE(Negate) diff --git a/include/Oasis/SimplifyVisitor.hpp b/include/Oasis/SimplifyVisitor.hpp new file mode 100644 index 00000000..8a60d100 --- /dev/null +++ b/include/Oasis/SimplifyVisitor.hpp @@ -0,0 +1,57 @@ +// +// Created by Andrew Nazareth on 9/23/25. +// + +#ifndef SIMPLIFYVISITOR_HPP +#define SIMPLIFYVISITOR_HPP + +#include +#include + +#include + +#include "Oasis/Visit.hpp" + +namespace Oasis { + +struct SimplifyOpts{ + enum class AngleUnits { + RADIANS, + DEGREES, + } angleUnits = AngleUnits::RADIANS; +}; + + +class SimplifyVisitor final : public TypedVisitor>, std::string>> { +public: + SimplifyVisitor(); + explicit SimplifyVisitor(SimplifyOpts& 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; + + [[nodiscard]] SimplifyOpts GetOptions() const; + +private: + SimplifyOpts options; +}; + +} // Oasis + +#endif // SIMPLIFYVISITOR_HPP diff --git a/include/Oasis/Sine.hpp b/include/Oasis/Sine.hpp new file mode 100644 index 00000000..c3bfd786 --- /dev/null +++ b/include/Oasis/Sine.hpp @@ -0,0 +1,42 @@ +// +// Created by Andrew Nazareth on 9/19/25. +// + +#ifndef OASIS_SINE_HPP +#define OASIS_SINE_HPP + +#include "UnaryExpression.hpp" + +namespace Oasis { + +template +class Sine; + +template <> +class Sine final : public UnaryExpression { +public: + Sine() = default; + Sine(const Sine& other) + : UnaryExpression(other) + { + } + + explicit Sine(const Expression& operand) + : UnaryExpression(operand) + { + } + + [[deprecated]] + [[nodiscard]] auto Simplify() const -> std::unique_ptr override; + + [[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) + EXPRESSION_CATEGORY(UnExp) +}; + +} // Oasis + +#endif // OASIS_SINE_HPP diff --git a/include/Oasis/Subtract.hpp b/include/Oasis/Subtract.hpp index c869dc51..0d31c49d 100644 --- a/include/Oasis/Subtract.hpp +++ b/include/Oasis/Subtract.hpp @@ -22,6 +22,7 @@ class Subtract : public BinaryExpression { Subtract(const Expression& minuend, const Expression& subtrahend); + [[deprecated]] [[nodiscard]] auto Simplify() const -> std::unique_ptr final; [[nodiscard]] auto Differentiate(const Expression& differentiationVariable) const -> std::unique_ptr final; diff --git a/include/Oasis/UnaryExpression.hpp b/include/Oasis/UnaryExpression.hpp index 5f5395ca..87da2c63 100644 --- a/include/Oasis/UnaryExpression.hpp +++ b/include/Oasis/UnaryExpression.hpp @@ -10,7 +10,7 @@ namespace Oasis { -template