diff --git a/QuicMaf/QuicMaf.vcxproj b/QuicMaf/QuicMaf.vcxproj
index 9e5de4f..ea07cf6 100644
--- a/QuicMaf/QuicMaf.vcxproj
+++ b/QuicMaf/QuicMaf.vcxproj
@@ -131,6 +131,7 @@
+
diff --git a/QuicMaf/QuicMaf.vcxproj.filters b/QuicMaf/QuicMaf.vcxproj.filters
index 1241da6..ccaf52c 100644
--- a/QuicMaf/QuicMaf.vcxproj.filters
+++ b/QuicMaf/QuicMaf.vcxproj.filters
@@ -74,5 +74,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/QuicMaf/app.cpp b/QuicMaf/app.cpp
index 8e81254..ac1a3ca 100644
--- a/QuicMaf/app.cpp
+++ b/QuicMaf/app.cpp
@@ -70,13 +70,15 @@ int main() {
int main() {
lexertk::generator lexer;
- lexer.process("2(x + 2x) + 2x");
+ lexer.process("2x/(4x+2)");
auto result = tokenize(lexer);
QMReducer reducer;
reducer.setPool(result);
- auto res = reducer.Sub(result[0], result[2]);
+ auto frac = static_cast(result[0]);
+
+ auto res = reducer.Div(frac->mNomin[0], frac->mDomin[0]);
return 0;
}
diff --git a/QuicMaf/maths/defines.h b/QuicMaf/maths/defines.h
index 7b1de31..9382791 100644
--- a/QuicMaf/maths/defines.h
+++ b/QuicMaf/maths/defines.h
@@ -29,6 +29,7 @@ enum TermTypes {
Op,
Brack,
Equ,
+ Frac,
};
// for string delimiter
diff --git a/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp b/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp
index 9adb506..c7f736b 100644
--- a/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp
+++ b/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp
@@ -63,7 +63,7 @@ Bracket * QMReducer::convertToBracket(Term * t1) {
if (t1->mType != TermTypes::Brack) return false;
return static_cast(t1);
}
-Variable * QMReducer::converToVariable(Term * t1) {
+Variable * QMReducer::convertToVariable(Term * t1) {
if (t1->mType != TermTypes::Var) return false;
return static_cast(t1);
}
@@ -190,8 +190,8 @@ vector QMReducer::Add(Term * t1, Term * t2, Identifier_t order) {
return { Const };
}
else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) {
- auto t1_var = converToVariable(t1);
- auto t2_var = converToVariable(t2);
+ auto t1_var = convertToVariable(t1);
+ auto t2_var = convertToVariable(t2);
Variable* var = nullptr;
var = new Variable();
@@ -265,8 +265,8 @@ vector QMReducer::Sub(Term * t1, Term * t2, Identifier_t order) {
return { Const };
}
else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) {
- auto t1_var = converToVariable(t1);
- auto t2_var = converToVariable(t2);
+ auto t1_var = convertToVariable(t1);
+ auto t2_var = convertToVariable(t2);
Variable* var = nullptr;
var = new Variable();
@@ -346,8 +346,8 @@ vector QMReducer::Mul(Term * t1, Term * t2, Identifier_t order) {
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);
+ auto t1_var = convertToVariable(t1);
+ auto t2_var = convertToVariable(t2);
Variable* var = nullptr;
var = new Variable();
@@ -357,7 +357,7 @@ vector QMReducer::Mul(Term * t1, Term * t2, Identifier_t order) {
return { var };
}
else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Const) {
- auto t1_var = converToVariable(t1);
+ auto t1_var = convertToVariable(t1);
auto t2_const = convertToConstant(ReducePower(t2)[0]);
Variable* var = nullptr;
@@ -369,7 +369,7 @@ vector QMReducer::Mul(Term * t1, Term * t2, Identifier_t order) {
}
else if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Var) {
auto t1_const = convertToConstant(t1);
- auto t2_var = converToVariable(ReducePower(t2)[0]);
+ auto t2_var = convertToVariable(ReducePower(t2)[0]);
Variable* var = nullptr;
var = new Variable();
@@ -391,3 +391,232 @@ vector QMReducer::Mul(Term * t1, Term * t2, Identifier_t order) {
}
return res;
}
+
+bool QMReducer::IsDivSolvable(Term * t1, Term * t2) {
+ if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) return true;
+ if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) return true;
+
+ return false;
+}
+
+bool QMReducer::IsDivSpecialCase(Term * t1, Term * t2) {
+ if (t1->mType == TermTypes::Brack &&
+ t2->mType != TermTypes::Brack) return true;
+
+ if (t1->mType != TermTypes::Brack &&
+ t2->mType == TermTypes::Brack) return true;
+
+ if (t1->mType == TermTypes::Brack &&
+ t2->mType == TermTypes::Brack) return true;
+
+ if (t1->mType == TermTypes::Const &&
+ t2->mType == TermTypes::Var) return true;
+
+ return false;
+}
+
+vector QMReducer::gcdofTerms(Term * t1, Term * t2) {
+
+ if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) {
+ auto t1_const = convertToConstant(ReducePower(t1)[0]);
+ auto t2_const = convertToConstant(ReducePower(t2)[0]);
+
+ Constant* Const = new Constant();
+ Const->mValue = gcf(t1->mValue, t2->mValue);
+ return { Const };
+ }
+ else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) {
+ auto t1_var = convertToVariable(t1);
+ auto t2_var = convertToVariable(t2);
+
+ Variable* var = new Variable();
+ var->mValue = gcf(t1_var->mValue, t2_var->mValue);
+ var->mVariable = t1_var->mVariable;
+ var->mPower = (t1_var->mPower > t2_var->mPower) ? t2_var->mPower : t1_var->mPower;
+
+ return { var };
+ }
+ else if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Const) {
+ auto t1_var = convertToVariable(t1);
+ auto t2_const = convertToConstant(t2);
+
+ Constant* Const = new Constant();
+ Const->mValue = gcf(t1_var->mValue, t2_const->mValue);
+ return { Const };
+ }
+ else if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Var) {
+ auto t1_const = convertToConstant(t1);
+ auto t2_var = convertToVariable(t2);
+
+ Constant* Const = new Constant();
+ Const->mValue = gcf(t1_const->mValue, t2_var->mValue);
+ return { Const };
+ }
+
+ return {};
+}
+
+vector QMReducer::FactorizeTermsToBrack(vector terms, vector terms2) {
+ vector allTerms = terms;
+ for (int i = 0; i < terms2.size(); i++)
+ allTerms.push_back(terms2[i]);
+
+ Term* HCF_all = new Term();
+ *HCF_all = *allTerms[0];
+ for (int i = 0; i < allTerms.size(); i++)
+ *HCF_all = *gcdofTerms(HCF_all, allTerms[i])[0];
+
+ // make first bracket
+ Bracket* brack1 = new Bracket();
+ brack1->setConstant(HCF_all);
+ for (int i = 0; i < terms.size(); i++)
+ brack1->mTerms.push_back(Div(terms[i], HCF_all)[0]);
+
+ // make second bracket
+ Bracket* brack2 = new Bracket();
+ brack2->setConstant(HCF_all);
+ for (int i = 0; i < terms2.size(); i++)
+ brack2->mTerms.push_back(Div(terms[i], HCF_all)[0]);
+
+ return { brack1, brack2 };
+}
+
+vector QMReducer::FactorizeTermsToBrack(vector allTerms) {
+ Term* HCF_all = new Term();
+ *HCF_all = *allTerms[0];
+ for (int i = 0; i < allTerms.size(); i++)
+ *HCF_all = *gcdofTerms(HCF_all, allTerms[i])[0];
+
+ // make bracket
+ Bracket* brack = new Bracket();
+ brack->setConstant(HCF_all);
+ for (int i = 0; i < allTerms.size(); i++)
+ brack->mTerms.push_back(Div(allTerms[i], HCF_all)[0]);
+
+ return { brack };
+}
+
+bool QMReducer::TermsMatch(vector terms1, vector terms2) {
+ terms1 = OrderTerms(terms1, Identifier_t::_high_order_left);
+ terms2 = OrderTerms(terms2, Identifier_t::_high_order_left);
+ return terms1 == terms2;
+}
+
+// WARNING: Make sure that t1 and t2 are in the simplest form.
+vector QMReducer::Div(Term * t1, Term * t2, Identifier_t order) {
+
+
+ // Check if division is solvable
+ if (IsDivSolvable(t1, t2)) {
+ // only two situations
+ // var / var, pow_no_matter
+ // const / const, pow_no_matter
+
+ if (t1->mType == TermTypes::Var && t2->mType == TermTypes::Var) {
+ // var / var
+ Term* res = new Term();
+ res->mValue = t1->mValue / t2->mValue;
+ res->mPower = t1->mPower - t2->mPower;
+ if (res->mPower == 0.0)
+ // it is a constant
+ res->mType = TermTypes::Const;
+ else
+ res->mVariable = t1->mVariable;
+ return { res };
+ }
+ else if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Const) {
+ // const / const
+ t1 = convertToConstant(ReducePower(t1)[0]);
+ t2 = convertToConstant(ReducePower(t2)[0]);
+
+ Constant* Const = new Constant();
+ Const->mValue = t1->mValue / t2->mValue;
+ return { Const };
+ }
+ }
+ // if it was a special case
+ else if (IsDivSpecialCase(t1, t2)) {
+ // only three situations:
+ // mult term / mult term
+ // one term const / one term var
+ // multi terms / one term
+ // one term / multi terms
+
+ if (t1->mType == TermTypes::Brack && t2->mType == TermTypes::Brack) {
+ // multi terms / multi term
+ auto t1_brack = convertToBracket(t1);
+ auto t2_brack = convertToBracket(t2);
+
+ // check if taking out common factors makes common bracket terms
+ auto fraction_nomin = convertToBracket(FactorizeTermsToBrack(t1_brack->mTerms)[0]);
+ auto fraction_domin = convertToBracket(FactorizeTermsToBrack(t2_brack->mTerms)[0]);
+
+ if (TermsMatch(fraction_nomin->mTerms, fraction_domin->mTerms))
+ // common bracket terms matched
+ // TIME FOR RECURSION!
+ return Div(fraction_nomin->GetConstant(), fraction_domin->GetConstant());
+
+ // check if taking out common factors make common bracket coeffiecient
+ auto fraction = FactorizeTermsToBrack(t1_brack->mTerms, t2_brack->mTerms);
+ // fraction[0] is nomin
+ // fraction[1] is domin
+ fraction_nomin = convertToBracket(fraction[0]);
+ fraction_nomin->setConstant(nullptr); // Nullptr == 1
+ fraction_domin = convertToBracket(fraction[1]);
+ fraction_domin->setConstant(nullptr); // Nullptr == 1
+
+ Fraction* frac = new Fraction();
+
+ frac->mNomin = fraction_nomin->mTerms;
+ frac->mDomin = fraction_domin->mTerms;
+ return { frac };
+ }
+ else if (t1->mType == TermTypes::Const && t2->mType == TermTypes::Var) {
+ // const / var
+ auto t1_const = convertToConstant(ReducePower(t1)[0]);
+ auto t2_var = convertToVariable(t2);
+
+ Variable* var = new Variable();
+ var->mVariable = t2_var->mVariable;
+ var->mValue = t1_const->mValue / t2_var->mValue;
+ var->mPower = t2_var->mPower;
+
+ return { var };
+ }
+ else if (t1->mType == TermTypes::Brack && t2->mType != TermTypes::Brack) {
+ // multi terms / multi terms
+ auto t1_brack = convertToBracket(t1);
+
+ vector result;
+ for (int i = 0; i < t1_brack->mTerms.size(); i++) {
+ if (t1_brack->mTerms[i]->mType == TermTypes::Op) {
+ result.push_back(t1_brack->mTerms[i]);
+ continue;
+ }
+
+ auto resultant = Div(t1_brack->mTerms[i], t2);
+ for (auto *term : resultant) result.push_back(term);
+ }
+
+ return result;
+ }
+ else if (t1->mType != TermTypes::Brack && t2->mType == TermTypes::Brack) {
+ // one term / multi terms
+ auto t2_Brack = convertToBracket(t2);
+
+ vector result;
+ for (int i = 0; i < t2_Brack->mTerms.size(); i++) {
+ if (t2_Brack->mTerms[i]->mType == TermTypes::Op) {
+ result.push_back(t2_Brack->mTerms[i]);
+ }
+
+ auto resultant = Div(t1, t2_Brack->mTerms[i]);
+ for (auto *term : resultant) result.push_back(term);
+ }
+
+ return result;
+ }
+ }
+
+ return {};
+}
diff --git a/QuicMaf/maths/solver/term_rewriter/QMReducer.h b/QuicMaf/maths/solver/term_rewriter/QMReducer.h
index 571c774..b2f5e1d 100644
--- a/QuicMaf/maths/solver/term_rewriter/QMReducer.h
+++ b/QuicMaf/maths/solver/term_rewriter/QMReducer.h
@@ -11,6 +11,7 @@
#include "../../terms/Term.h"
#include "../../terms/Variable.h"
#include "../../terms/Paranthesis.h"
+#include "../../terms/Fraction.h"
#include "../../tokenizer.h"
#include "../../../vendor/lexertk.hpp"
@@ -34,7 +35,7 @@ private: // General Utilites
vector getRangeOfTerms(vector terms, int begin, int end);
Bracket* convertToBracket(Term* t1);
- Variable* converToVariable(Term* t1);
+ Variable* convertToVariable(Term* t1);
Constant* convertToConstant(Term* t1);
bool IsHigherSig(Term* t1, Term* t2);
@@ -49,15 +50,26 @@ private: // General Utilites
private: // Power Evaluation
vector ReducePower(Term* t1);
-public: // Addition Evaluation // TODO: PUBLIC AFTER TESTING
+public: // Addition Evaluation // TODO: PRIVATE AFTER TESTING
vector Add(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left);
-public: // Subtraction Evaluation // TODO: PUBLIC AFTER TESTING
+public: // Subtraction Evaluation // TODO: PRIVATE AFTER TESTING
vector Sub(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left);
-public: // Multiplication Evaluation // TODO: PUBLIC AFTER TESTING
+public: // Multiplication Evaluation // TODO: PRIVATE AFTER TESTING
vector Mul(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left);
+public: // Division Evaluation // TODO: PRIVATE AFTER TESTING
+ bool IsDivSolvable(Term* t1, Term* t2);
+ bool IsDivSpecialCase(Term* t1, Term* t2);
+
+ vector gcdofTerms(Term* t1, Term* t2);
+ vector FactorizeTermsToBrack(vector terms, vector terms2);
+ vector FactorizeTermsToBrack(vector terms);
+
+ bool TermsMatch(vector terms1, vector terms2);
+
+ vector Div(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left);
private:
QMRuleSet mRuleSet;
diff --git a/QuicMaf/maths/terms/Fraction.h b/QuicMaf/maths/terms/Fraction.h
new file mode 100644
index 0000000..d9a98f9
--- /dev/null
+++ b/QuicMaf/maths/terms/Fraction.h
@@ -0,0 +1,21 @@
+#ifndef FRACTION_H
+#define FRACTION_H
+#pragma once
+#include "../defines.h"
+#include "Term.h"
+using namespace std;
+
+class Fraction: public Term {
+public:
+ Fraction(vector nomin = {}, vector domin = {}) {
+ Term();
+ mNomin = nomin;
+ mDomin = domin;
+ mType = TermTypes::Frac;
+ }
+
+public: // TODO: try to change to private
+ vector mNomin;
+ vector mDomin;
+};
+#endif // !CONSTANT_H
diff --git a/QuicMaf/maths/tokenizer.h b/QuicMaf/maths/tokenizer.h
index d6d464e..e4b228e 100644
--- a/QuicMaf/maths/tokenizer.h
+++ b/QuicMaf/maths/tokenizer.h
@@ -26,6 +26,7 @@
#include "terms/Term.h"
#include "terms/Variable.h"
#include "terms/Paranthesis.h"
+#include "terms/Fraction.h"
#include "../vendor/lexertk.hpp"
@@ -163,6 +164,43 @@ static vector combineBrackets(vector terms) {
return result;
}
+static vector combineOpWithTerms(vector terms) {
+ vector result;
+
+ for (int i = 0; i < terms.size(); i++) {
+ if (terms[i]->mType == TermTypes::Op) {
+ // operator detected
+ auto op = static_cast(terms[i]);
+ if (op->mOperator == '/') {
+ // division found
+
+ // check if it was the first
+ if (i == 0) {
+ // invalid
+ cout << "Can't divide with a Nill nominator!" << endl;
+ system("PAUSE");
+ exit(0);
+ }
+
+
+ Fraction* frac = new Fraction();
+ frac->mDomin.push_back(terms[i + 1]);
+ frac->mNomin.push_back(terms[i - 1]);
+ result.pop_back(); // pop the nominator, before push
+ result.push_back(frac);
+
+ // consume the dominator
+ i += 1;
+ continue;
+ }
+ }
+ result.push_back(terms[i]);
+ continue;
+ }
+
+ return result;
+}
+
static vector tokenize(lexertk::generator lexed) {
vector result;
@@ -321,8 +359,9 @@ static vector tokenize(lexertk::generator lexed) {
i = tok.end; // no need to increment, automatically done in loop statment
}
+ // post-fix fixes
result = combineBrackets(result);
-
+ result = combineOpWithTerms(result);
return result;
}
#endif // !TOKENIZER_H
diff --git a/bin/Debug-x64/QuicMaf.exe b/bin/Debug-x64/QuicMaf.exe
index 9d37baa..052f193 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 a82b6ea..04d13b6 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 183f35e..b5d9816 100644
Binary files a/bin/Debug-x64/QuicMaf.pdb and b/bin/Debug-x64/QuicMaf.pdb differ