QuicMaf/QuicMaf/maths/solver/term_rewriter/QMReducer.cpp

623 lines
19 KiB
C++

#include "QMReducer.h"
vector<Term*> QMReducer::Reduce() {
return vector<Term*>();
}
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<Term*> QMReducer::BreakBracket(Bracket * brack, bool order, Identifier_t order_type) {
vector<Term*> 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<Term*> QMReducer::OrderTerms(vector<Term*> terms, Identifier_t order) {
stable_sort(terms.begin(), terms.end(), [this](Term* t1, Term* t2) {return IsHigherSig(t1, t2); });
return terms;
}
vector<Term*> QMReducer::getRangeOfTerms(vector<Term*> terms, int begin, int end) {
vector<Term*> 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<Bracket*>(t1);
}
Variable * QMReducer::convertToVariable(Term * t1) {
if (t1->mType != TermTypes::Var) return false;
return static_cast<Variable*>(t1);
}
Constant * QMReducer::convertToConstant(Term * t1) {
if (t1->mType != TermTypes::Const) return false;
return static_cast<Constant*>(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<Term*> 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<Term*> QMReducer::Add(Term * t1, Term * t2, Identifier_t order) {
vector<Term*> 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 = convertToVariable(t1);
auto t2_var = convertToVariable(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<Term*> QMReducer::Sub(Term * t1, Term * t2, Identifier_t order) {
vector<Term*> 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 = convertToVariable(t1);
auto t2_var = convertToVariable(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<Term*> QMReducer::Mul(Term * t1, Term * t2, Identifier_t order) {
vector<Term*> 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 = convertToVariable(t1);
auto t2_var = convertToVariable(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 = convertToVariable(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 = convertToVariable(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;
}
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 {};
}