Made Unfinished Divisions

This commit is contained in:
Ayham Mamoun 2019-03-11 20:05:23 +03:00
parent cc743f1e54
commit cd74a89e25
11 changed files with 324 additions and 16 deletions

View File

@ -131,6 +131,7 @@
<ClInclude Include="maths\terms\Brackets.h" />
<ClInclude Include="maths\terms\Constant.h" />
<ClInclude Include="maths\terms\Equal.h" />
<ClInclude Include="maths\terms\Fraction.h" />
<ClInclude Include="maths\terms\Operator.h" />
<ClInclude Include="maths\terms\Paranthesis.h" />
<ClInclude Include="maths\terms\Term.h" />

View File

@ -74,5 +74,8 @@
<ClInclude Include="maths\solver\term_rewriter\QMReducer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="maths\terms\Fraction.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -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<Fraction*>(result[0]);
auto res = reducer.Div(frac->mNomin[0], frac->mDomin[0]);
return 0;
}

View File

@ -29,6 +29,7 @@ enum TermTypes {
Op,
Brack,
Equ,
Frac,
};
// for string delimiter

View File

@ -63,7 +63,7 @@ Bracket * QMReducer::convertToBracket(Term * t1) {
if (t1->mType != TermTypes::Brack) return false;
return static_cast<Bracket*>(t1);
}
Variable * QMReducer::converToVariable(Term * t1) {
Variable * QMReducer::convertToVariable(Term * t1) {
if (t1->mType != TermTypes::Var) return false;
return static_cast<Variable*>(t1);
}
@ -190,8 +190,8 @@ vector<Term*> 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<Term*> 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<Term*> 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<Term*> 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<Term*> 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<Term*> 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<Term*> 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<Term*> QMReducer::FactorizeTermsToBrack(vector<Term*> terms, vector<Term*> terms2) {
vector<Term*> 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<Term*> QMReducer::FactorizeTermsToBrack(vector<Term*> 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<Term*> terms1, vector<Term*> 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<Term*> 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<Term*> 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<Term*> 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 {};
}

View File

@ -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<Term*> getRangeOfTerms(vector<Term*> 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<Term*> ReducePower(Term* t1);
public: // Addition Evaluation // TODO: PUBLIC AFTER TESTING
public: // Addition Evaluation // TODO: PRIVATE AFTER TESTING
vector<Term*> 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<Term*> 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<Term*> 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<Term*> gcdofTerms(Term* t1, Term* t2);
vector<Term*> FactorizeTermsToBrack(vector<Term*> terms, vector<Term*> terms2);
vector<Term*> FactorizeTermsToBrack(vector<Term*> terms);
bool TermsMatch(vector<Term*> terms1, vector<Term*> terms2);
vector<Term*> Div(Term* t1, Term* t2, Identifier_t order = Identifier_t::_high_order_left);
private:
QMRuleSet mRuleSet;

View File

@ -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<Term*> nomin = {}, vector<Term*> domin = {}) {
Term();
mNomin = nomin;
mDomin = domin;
mType = TermTypes::Frac;
}
public: // TODO: try to change to private
vector<Term*> mNomin;
vector<Term*> mDomin;
};
#endif // !CONSTANT_H

View File

@ -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<Term*> combineBrackets(vector<Term*> terms) {
return result;
}
static vector<Term*> combineOpWithTerms(vector<Term*> terms) {
vector<Term*> result;
for (int i = 0; i < terms.size(); i++) {
if (terms[i]->mType == TermTypes::Op) {
// operator detected
auto op = static_cast<Operator*>(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<Term*> tokenize(lexertk::generator lexed) {
vector<Term*> result;
@ -321,8 +359,9 @@ static vector<Term*> 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

Binary file not shown.

Binary file not shown.

Binary file not shown.