diff --git a/QMReducer Function Callers and Clalling.txt b/QMReducer Function Callers and Clalling.txt new file mode 100644 index 0000000..eb9f500 --- /dev/null +++ b/QMReducer Function Callers and Clalling.txt @@ -0,0 +1,66 @@ +QMReducer Functions Calling, and Callers: + +General Utilities Functions: + IsSolvable: + Callings: + Callers: Add, Sub + BreakBrackets: + Callings: Mul + Callers: Add, Sub + OrderTerms: + Callings: IsHigherSig + Callers: + GetRangeTerms: + Callings: + Callers: + ConverttoBracket: + Callings: + Callers: Add, Sub + ConvertToVariable: + Callings: + Callers: Add, Sub + ConvertToConstant: + Callings: + Callers: Add, Sub + IsHigherSig: + Callings: + Calelrs: OrderTerms + IsEquTerms: + Callings: + IsEquTypes, IsEquPower, IsEquValue, IsEquVariable + Callers: + IsEquTypes: + Callings: + Callers: IsEquTerms + IsEquPower: + Callings: + Callers: IsEquTerms + IsEquValue: + Callings: + Callers: IsEquTerms + IsEquVaraible: + Callings: + Callers: IsEquTerms + IsBracket: + Callings: + Callers: Add, Sum + +Power Evaluation: + ReducePower: + Callings: Mul + Callers: Add, Sub + +Addition Evaluation: + Add: + Callings: IsBracket, BreakBracket, convertTo*, IsSolvable, ReducePower, OrderTerms + Callers: + +Subtraction Evaluation: + Sub: + Callings: IsBracket, BreakBracket, convertTo*, IsSolvable, ReducePower, OrderTerms + Callers: + +Multiplication Evaluation: + Mul: + Callings: Mul, IsBracket, BreakBracket, convertTo*, ReducePower + Callers: ReducePower, BreakBracket \ No newline at end of file diff --git a/QuicMaf/QuicMaf.vcxproj b/QuicMaf/QuicMaf.vcxproj index 86a8195..9e5de4f 100644 --- a/QuicMaf/QuicMaf.vcxproj +++ b/QuicMaf/QuicMaf.vcxproj @@ -120,7 +120,7 @@ - + diff --git a/QuicMaf/QuicMaf.vcxproj.filters b/QuicMaf/QuicMaf.vcxproj.filters index bc41458..1241da6 100644 --- a/QuicMaf/QuicMaf.vcxproj.filters +++ b/QuicMaf/QuicMaf.vcxproj.filters @@ -24,7 +24,7 @@ Source Files - + Source Files diff --git a/QuicMaf/app.cpp b/QuicMaf/app.cpp index 67af4c3..8e81254 100644 --- a/QuicMaf/app.cpp +++ b/QuicMaf/app.cpp @@ -8,6 +8,8 @@ #include "maths/solver/Solver.h" #include "maths/Equations.h" +#include "maths/solver/term_rewriter/QMReducer.h" + //#define MAIN_APP #define APP_TEST @@ -68,10 +70,13 @@ int main() { int main() { lexertk::generator lexer; - lexer.process("_const+_const,_eval:no_diff_Var"); + lexer.process("2(x + 2x) + 2x"); - //auto result = tokenize(lexer); + auto result = tokenize(lexer); + QMReducer reducer; + reducer.setPool(result); + auto res = reducer.Sub(result[0], result[2]); return 0; } diff --git a/QuicMaf/maths/defines.h b/QuicMaf/maths/defines.h index 44596e1..7b1de31 100644 --- a/QuicMaf/maths/defines.h +++ b/QuicMaf/maths/defines.h @@ -13,6 +13,8 @@ #include #include +#include + using namespace std; #define DEF_C -999 diff --git a/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp b/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp new file mode 100644 index 0000000..9adb506 --- /dev/null +++ b/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp @@ -0,0 +1,393 @@ +#include "QMReducer.h" + +vector QMReducer::Reduce() { + return vector(); +} + +bool QMReducer::IsSolvable(Term * t1, Operator * op, Term * t2) { + // Constants check + if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) return true; + if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var && + op->mOperator == '*') return true; + + // Variables check + if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var && + IsEquPower(t1, t2)) return true; + if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var && + !IsEquPower(t1, t2)) return false; + + // Brackets checks + // Avoid calling is solvable on bracket since they will break + // in evaluation process + if (t1->mType == TermTypes::Brack && t2->mType == TermTypes::Brack && + op->mOperator == '*') return true; + if (t1->mType == TermTypes::Brack && t2->mType != TermTypes::Brack && + op->mOperator == '*') return true; + if (t2->mType == TermTypes::Brack && t1->mType != TermTypes::Brack && + op->mOperator == '*') return true; + if (t1->mType == TermTypes::Brack && t2->mType != TermTypes::Brack && + op->mOperator != '*') return true; + if (t2->mType == TermTypes::Brack && t1->mType != TermTypes::Brack && + op->mOperator != '*') return true; + + return false; // End situation +} +vector QMReducer::BreakBracket(Bracket * brack, bool order, Identifier_t order_type) { + vector res; + + if (brack->GetConstant() == nullptr) { + for (int i = 0; i < brack->mTerms.size(); i++) + res.push_back(brack->mTerms[i]); + } + + for (int i = 0; i < brack->mTerms.size(); i++) { + auto returns = Mul(brack->GetConstant(), brack->mTerms[i]); + for (int j = 0; j < returns.size(); j++) + res.push_back(returns[j]); + } + return res; +} + +vector QMReducer::OrderTerms(vector terms, Identifier_t order) { + stable_sort(terms.begin(), terms.end(), [this](Term* t1, Term* t2) {return IsHigherSig(t1, t2); }); + return terms; +} +vector QMReducer::getRangeOfTerms(vector terms, int begin, int end) { + vector res; + for (int i = begin; i < end; i++) res.push_back(terms[i]); + return res; + return res; +} + +Bracket * QMReducer::convertToBracket(Term * t1) { + if (t1->mType != TermTypes::Brack) return false; + return static_cast(t1); +} +Variable * QMReducer::converToVariable(Term * t1) { + if (t1->mType != TermTypes::Var) return false; + return static_cast(t1); +} +Constant * QMReducer::convertToConstant(Term * t1) { + if (t1->mType != TermTypes::Const) return false; + return static_cast(t1); +} + +bool QMReducer::IsHigherSig(Term * t1, Term * t2) { // x^2 > x : true + if (t1->mType == TermTypes::Brack) + return true; + else if (t1->mType == TermTypes::Op) + return false; + else if (t2->mType == TermTypes::Op) + return true; + if (t1->mType == TermTypes::Var) { + // its a var check for other term + if (t2->mType == TermTypes::Brack) return false; + + if (t2->mType == TermTypes::Var) { + // if power is equal + if (IsEquPower(t1, t2)) { + // check for value + return t1->mValue >= t2->mValue; + } + // if t1 has higher or equal power + if (t1->mPower >= t2->mPower) return true; + else return false; // t2 is higher + } + + return true; + } + else if (t1->mType == TermTypes::Const) { + // its a const check for other term + if (t2->mType == TermTypes::Brack) return false; + if (t2->mType == TermTypes::Var) return false; + if (t2->mType == TermTypes::Const) { + // if same type + // check for power + return t1->mPower >= t2->mPower; + } + } + + return false; +} + +bool QMReducer::IsEquTerms(Term * t1, Term * t2) { + if (!IsEquTypes(t1, t2)) return false; + if (!IsEquPower(t1, t2)) return false; + if (!IsEquValue(t1, t2)) return false; + if (!IsEquVariable(t1, t2)) return false; + return true; +} + +bool QMReducer::IsEquTypes(Term * t1, Term * t2) { + return t1->mType == t2->mType; +} +bool QMReducer::IsEquPower(Term * t1, Term * t2) { + return t1->mPower == t2->mPower; +} +bool QMReducer::IsEquValue(Term * t1, Term * t2) { + return t1->mValue == t2->mValue; +} +bool QMReducer::IsEquVariable(Term * t1, Term * t2) { + return t1->mVariable == t2->mVariable; +} +bool QMReducer::IsBracket(Term * t1) { + return t1->mType == TermTypes::Brack; +} + +vector QMReducer::ReducePower(Term * t1) { + if (IsBracket(t1)) return {}; // Brackets powers aren't allowed + + if (t1->mType == TermTypes::Var) return { t1 }; + else + t1->mValue = pow(t1->mValue, t1->mPower); + + return { t1 }; +} + +vector QMReducer::Add(Term * t1, Term * t2, Identifier_t order) { + vector res; + + + // check if one of the terms were brackets + if (IsBracket(t1) || IsBracket(t2)) { + // check which term is bracket + if (IsBracket(t1) && !IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t1)); + auto brokenbrack2 = BreakBracket(convertToBracket(t2)); + for (int i = 0; i < brokenbrack2.size(); i++) + brokenbrack.push_back(brokenbrack[i]); + // TODO: evaluation system + return brokenbrack; + } + if (IsBracket(t1) && !IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t1)); + brokenbrack.push_back(t2); + // TODO: evaluation system + return brokenbrack; + } + else if (!IsBracket(t1) && IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t2)); + brokenbrack.push_back(t1); + // TODO: evaluation system + return brokenbrack; + } + } + else { + // Check if it was solvable + if (IsSolvable(t1, new Operator('+'), t2)) { + // only two cases that it is solvable + // const + const + // var + var : no var difference + if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) { + auto t1_const = convertToConstant(t1); + auto t2_const = convertToConstant(t2); + t1_const = convertToConstant(ReducePower(t1_const)[0]); + t2_const = convertToConstant(ReducePower(t2_const)[0]); + + Constant* Const = nullptr; + Const = new Constant(); + Const->mValue = t1_const->mValue + t2->mValue; + return { Const }; + } + else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) { + auto t1_var = converToVariable(t1); + auto t2_var = converToVariable(t2); + + Variable* var = nullptr; + var = new Variable(); + var->mPower = t1_var->mPower; + var->mValue = t1_var->mValue + t2_var->mValue; + if (var->mValue == 0) { + Constant* Const = nullptr; + Const->mPower = t1_var->mPower; + Const->mValue = t1_var->mValue + t2_var->mValue; + return { Const }; + } + var->mVariable = t1_var->mVariable; + return { var }; + } + } + else { // if it wasn't solvable + // only 3 situations it is not solvable + // these situations are treated the same + // order them depending on arg 'order' + res = { t1, t2 }; + res = OrderTerms(res, order); + return res; + } + } + return res; +} + +vector QMReducer::Sub(Term * t1, Term * t2, Identifier_t order) { + vector res; + + + // check if one of the terms were brackets + if (IsBracket(t1) || IsBracket(t2)) { + // check which term is bracket + if (IsBracket(t1) && IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t1)); + auto brokenbrack2 = BreakBracket(convertToBracket(t2)); + for (int i = 0; i < brokenbrack2.size(); i++) + brokenbrack.push_back(brokenbrack[i]); + // TODO: evaluation system + return brokenbrack; + } + if (IsBracket(t1) && !IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t1)); + brokenbrack.push_back(t2); + // TODO: evaluation system + return brokenbrack; + } + else if (!IsBracket(t1) && IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t2)); + brokenbrack.push_back(t1); + // TODO: evaluation system + return brokenbrack; + } + } + else { + // Check if it was solvable + if (IsSolvable(t1, new Operator('-'), t2)) { + // only two cases that it is solvable + // const + const + // var + var : no var difference + if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) { + auto t1_const = convertToConstant(t1); + auto t2_const = convertToConstant(t2); + t1_const = convertToConstant(ReducePower(t1_const)[0]); + t2_const = convertToConstant(ReducePower(t2_const)[0]); + + Constant* Const = nullptr; + Const = new Constant(); + Const->mValue = t1_const->mValue - t2->mValue; + return { Const }; + } + else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) { + auto t1_var = converToVariable(t1); + auto t2_var = converToVariable(t2); + + Variable* var = nullptr; + var = new Variable(); + var->mPower = t1_var->mPower; + var->mValue = t1_var->mValue - t2_var->mValue; + if (var->mValue == 0) { + Constant* Const = new Constant(); + Const->mPower = t1_var->mPower; + Const->mValue = t1_var->mValue - t2_var->mValue; + return { Const }; + } + var->mVariable = t1_var->mVariable; + return { var }; + } + } + else { // if it wasn't solvable + // only 3 situations it is not solvable + // these situations are treated the same + // order them depending on arg 'order' + res = { t1, t2 }; + res = OrderTerms(res, order); + return res; + } + } + return res; +} + +vector QMReducer::Mul(Term * t1, Term * t2, Identifier_t order) { + vector res; + + // check if one of the terms are brackets + if (IsBracket(t1) || IsBracket(t2)) { + // only 3 situations + // brack, brack : use foil + // brack, var + // brack, const + + if (IsBracket(t1) || IsBracket(t2)) { + auto t1_brokenbrack = BreakBracket(convertToBracket(t1), true, order); + auto t2_brokenbrack = BreakBracket(convertToBracket(t2), true, order); + + for (int i = 0; i < t1_brokenbrack.size(); i++) { + for (int j = 0; j < t2_brokenbrack.size(); j++) { + auto returns = Mul(t1_brokenbrack[i], t2_brokenbrack[j], order); // recurse + for (int m = 0; m < returns.size(); m++) res.push_back(returns[m]); + } + } + + // TODO: Make evaluation system + return res; + } + // if only one bracket is there + if (IsBracket(t1) && !IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t1), true, order); + + // if t2 was a variable or a constant same method + for (int i = 0; i < brokenbrack.size(); i++) { + auto returns = Mul(brokenbrack[i], t2); + for (int j = 0; j < returns.size(); j++) res.push_back(returns[j]); + } + return res; + } + if (!IsBracket(t1) && IsBracket(t2)) { + auto brokenbrack = BreakBracket(convertToBracket(t2), true, order); + + // if t2 was a variable or a constant same method + for (int i = 0; i < brokenbrack.size(); i++) { + auto returns = Mul(brokenbrack[i], t1); + for (int j = 0; j < returns.size(); j++) res.push_back(returns[j]); + } + return res; + } + + + } + // niether are brackets + else { + // no need to check solvability + if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) { + auto t1_var = converToVariable(t1); + auto t2_var = converToVariable(t2); + + Variable* var = nullptr; + var = new Variable(); + var->mValue = t1_var->mValue * t2_var->mValue; + var->mVariable = t1_var->mVariable; + var->mPower = t1_var->mPower + t2_var->mPower; + return { var }; + } + else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Const) { + auto t1_var = converToVariable(t1); + auto t2_const = convertToConstant(ReducePower(t2)[0]); + + Variable* var = nullptr; + var = new Variable(); + var->mValue = t1_var->mValue * t2_const->mValue; + var->mVariable = t1_var->mVariable; + var->mPower = t1_var->mPower; + return { var }; + } + else if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Var) { + auto t1_const = convertToConstant(t1); + auto t2_var = converToVariable(ReducePower(t2)[0]); + + Variable* var = nullptr; + var = new Variable(); + var->mValue = t2_var->mValue * t1_const->mValue; + var->mVariable = t2_var->mVariable; + var->mPower = t2_var->mPower; + return { var }; + } + else if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) { + Constant* t1_const = new Constant(), *t2_const = new Constant(); + t1_const = convertToConstant(ReducePower(t1)[0]); + t2_const = convertToConstant(ReducePower(t2)[0]); + + Constant* Const = nullptr; + Const = new Constant(); + Const->mValue = t1_const->mValue * t2_const->mValue; + return { Const }; + } + } + return res; +} diff --git a/QuicMaf/maths/solver/term_rewriter/QMReducer.h b/QuicMaf/maths/solver/term_rewriter/QMReducer.h index 6f70f09..571c774 100644 --- a/QuicMaf/maths/solver/term_rewriter/QMReducer.h +++ b/QuicMaf/maths/solver/term_rewriter/QMReducer.h @@ -1 +1,67 @@ +#ifndef QMREDUCER_H +#define QMREDUCER_H #pragma once + +#include "../../Equations.h" +#include "../../defines.h" +#include "../../terms/Brackets.h" +#include "../../terms/Constant.h" +#include "../../terms/Equal.h" +#include "../../terms/Operator.h" +#include "../../terms/Term.h" +#include "../../terms/Variable.h" +#include "../../terms/Paranthesis.h" +#include "../../tokenizer.h" + +#include "../../../vendor/lexertk.hpp" + +#include "QMRule.h" +#include "QMRuleSet.h" + +// WARINING: Only one variable is allowed or errors will happen! + +class QMReducer { +public: + void setRuleSet(QMRuleSet set) { mRuleSet = set; }; + void setPool(vector terms) { mPool = terms; }; + + vector Reduce(); + +private: // General Utilites + bool IsSolvable(Term* t1, Operator* op, Term* t2); + vector BreakBracket(Bracket* brack, bool order = false, Identifier_t order_type = Identifier_t::_high_order_left); + vector OrderTerms(vector terms, Identifier_t order); + vector getRangeOfTerms(vector terms, int begin, int end); + + Bracket* convertToBracket(Term* t1); + Variable* converToVariable(Term* t1); + Constant* convertToConstant(Term* t1); + + bool IsHigherSig(Term* t1, Term* t2); + + bool IsEquTerms(Term* t1, Term* t2); + bool IsEquTypes(Term* t1, Term* t2); + bool IsEquPower(Term* t1, Term* t2); + bool IsEquValue(Term* t1, Term* t2); + bool IsEquVariable(Term* t1, Term* t2); + bool IsBracket(Term* t1); + +private: // Power Evaluation + vector ReducePower(Term* t1); + +public: // Addition Evaluation // TODO: PUBLIC AFTER TESTING + vector Add(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left); + +public: // Subtraction Evaluation // TODO: PUBLIC AFTER TESTING + vector Sub(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left); + +public: // Multiplication Evaluation // TODO: PUBLIC AFTER TESTING + vector Mul(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left); + +private: + QMRuleSet mRuleSet; + + vector mPool; +}; + +#endif // !QMREDUCER_H diff --git a/QuicMaf/maths/solver/term_rewriter/QMRule.cpp b/QuicMaf/maths/solver/term_rewriter/QMRule.cpp deleted file mode 100644 index fc05a48..0000000 --- a/QuicMaf/maths/solver/term_rewriter/QMRule.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "QMRule.h" - -vector QMRule::Reduce() -{ - return vector(); -} diff --git a/QuicMaf/maths/solver/term_rewriter/QMRule.h b/QuicMaf/maths/solver/term_rewriter/QMRule.h index b3481d7..1e17b6c 100644 --- a/QuicMaf/maths/solver/term_rewriter/QMRule.h +++ b/QuicMaf/maths/solver/term_rewriter/QMRule.h @@ -60,12 +60,7 @@ public: bool operator<(const QMRule& left) const { return (left.mPrior < mPrior); } - - vector Reduce(vector terms); // applies self rule on terms vector, only once private: - vector Evaluate(); // evaluation method - - vector mRules; vector mProps; int mPrior; diff --git a/QuicMaf/maths/solver/term_rewriter/QMRuleSet.h b/QuicMaf/maths/solver/term_rewriter/QMRuleSet.h index 6c08446..ed4da4e 100644 --- a/QuicMaf/maths/solver/term_rewriter/QMRuleSet.h +++ b/QuicMaf/maths/solver/term_rewriter/QMRuleSet.h @@ -18,16 +18,24 @@ class QMRuleSet { public: - void push_back(QMRule rule); - void push_front(QMRule rule); + void push_back(QMRule rule) { mRuleSet.push_back(rule); } + void push_front(QMRule rule) { mRuleSet.push_front(rule); } - void pop_back(QMRule rule); - void pop_front(QMRule rule); + void pop_back() { mRuleSet.pop_back(); }; + void pop_front() { mRuleSet.pop_front(); } - void order(); + QMRule back() { return mRuleSet[mRuleSet.size() - 1]; } + QMRule front() { return mRuleSet[0]; } + + void order() { + stable_sort(mRuleSet.begin(), mRuleSet.end()); + } auto GetRuleSet() { return mRuleSet; } + inline QMRule& operator[](int index) { + return mRuleSet[index]; + } private: deque mRuleSet; }; diff --git a/QuicMaf/maths/terms/Brackets.h b/QuicMaf/maths/terms/Brackets.h index 7a5e5b9..00359a3 100644 --- a/QuicMaf/maths/terms/Brackets.h +++ b/QuicMaf/maths/terms/Brackets.h @@ -30,6 +30,6 @@ public: Term* GetConstant() const { return mConstant; } private: - Term *mConstant; + Term *mConstant = nullptr; // Nullptr == 1 }; #endif // !BRACKET_H diff --git a/QuicMaf/maths/terms/Paranthesis.h b/QuicMaf/maths/terms/Paranthesis.h index 9374bea..6277689 100644 --- a/QuicMaf/maths/terms/Paranthesis.h +++ b/QuicMaf/maths/terms/Paranthesis.h @@ -19,8 +19,8 @@ class Paranthesis : Term { bool isOpening() { return __isopening; } int getType() { return __type; } - void setOpening(bool is) { __isopening == is; } - void setType(char type) { __type == type; } + void setOpening(bool is) { __isopening = is; } + void setType(char type) { __type = type; } private: bool __isopening = true; diff --git a/bin/Debug-x64/QuicMaf.exe b/bin/Debug-x64/QuicMaf.exe index ad45554..9d37baa 100644 Binary files a/bin/Debug-x64/QuicMaf.exe and b/bin/Debug-x64/QuicMaf.exe differ diff --git a/bin/Debug-x64/QuicMaf.ilk b/bin/Debug-x64/QuicMaf.ilk index 566f227..a82b6ea 100644 Binary files a/bin/Debug-x64/QuicMaf.ilk and b/bin/Debug-x64/QuicMaf.ilk differ diff --git a/bin/Debug-x64/QuicMaf.pdb b/bin/Debug-x64/QuicMaf.pdb index b07b581..183f35e 100644 Binary files a/bin/Debug-x64/QuicMaf.pdb and b/bin/Debug-x64/QuicMaf.pdb differ