Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions src/CalcManager/CEngine/PartialFrac.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
#include "PartialFrac.h"

PartialFrac::PartialFrac()
{

}

std::string PartialFrac::PartialFracDecomp(std::string equation)
{
std::vector<std::string> fraction = splitEquationString(equation);
std::string num = fraction[0];
std::string denom = fraction[1];
std::vector<PartialFrac::factor> factoredNum;
std::vector<PartialFrac::factor> factoredDenom;
factoredNum = factorExpr(num);
factoredDenom = factorExpr(denom);
std::vector<std::vector<int>> coeffMatrix = createCoeffMatrix(factoredNum, factoredDenom);
std::vector<int> coeff = solveMatrix(coeffMatrix);
std::vector<std::string> factors = splitDenom(denom);
std::string finalstring = stringBuilder(coeff, factors);
return finalstring;
}

std::vector<std::string> PartialFrac::splitEquationString(std::string equation)
{
std::vector<std::string> tmp;
tmp.resize(2);
//the following find statements scan for all types of ways the user could have typed their equation
size_t pos = equation.find(")/(");
if (pos != std::string::npos)
{
tmp[0] = equation.substr(0, pos + 1);
tmp[1] = equation.substr(pos + 2, equation.length());
return tmp;
}
pos = equation.find(")/");
if (pos != std::string::npos)
{
tmp[0] = equation.substr(0, pos + 1);
tmp[1] = equation.substr(pos + 2, equation.length());
return tmp;
}
pos = equation.find("/(");
if (pos != std::string::npos)
{
tmp[0] = equation.substr(0, pos);
tmp[1] = equation.substr(pos + 1, equation.length());
return tmp;
}
pos = equation.find("/");
if (pos != std::string::npos)
{
tmp[0] = equation.substr(0, pos);
tmp[1] = equation.substr(pos + 1, equation.length());
return tmp;
}
else
{
throw "Error in splitEquationString method; could not find a division symbol";
}
}

//bool PartialFrac::factoredForm(std::string denom)
//{
// int pos = denom.find("^");
// if (pos == std::string::npos)
// return true;
// else
// return false;
//}

std::vector<PartialFrac::factor> PartialFrac::factorExpr(std::string equation)
{
//probably going to use some Algebra class logic here, so I am going to leave this blank for now
throw "Not implemented";
}

std::vector<std::vector<int>> PartialFrac::createCoeffMatrix(std::vector<PartialFrac::factor> num, std::vector<PartialFrac::factor> denom)
{
//finding the RHS equation
//for each position, the value is equal to all other positions multiplied together.
std::vector<std::string> RHSexpressions;
std::string LHSexpression;
for (int i = 0; i < denom.size(); i++)
{
std::string expression;
for (int j = 0; j < denom.size(); j++)
{
if (i != j)
{
std::string tmp = "(" + denom[j].variable + " " + denom[j].operation + " " + std::to_string(denom[j].constant) + ")";
if (j == denom.size() - 1)
expression += tmp;
else
expression += tmp + " * ";
}
}
//Algebra intermediate = Algebra(expression);
//intermediate.format();
//RHSexpressions.push_back(intermediate.simplifyExpression());
}

//finding LHS expression
std::string expression;
for (int i = 0; i < num.size(); i++)
{
std::string tmp = "(" + num[i].variable + " " + num[i].operation + " " + std::to_string(num[i].constant) + ")";
if (i == num.size() - 1)
expression += tmp;
else
expression += tmp + " * ";
}
// Algebra intermediate = Algebra(expression);
// intermediate.format();
// LHSexpression = intermediate.simplifyExpression();

//creating the matrix to store the values; I am resizing the vectors since I need to start at the bottom right instead of the top left
std::vector<std::vector<int>> matrix;
matrix.resize(RHSexpressions.size() + 1);
for (int i = 0; i < matrix.size(); i++)
{
matrix[i].resize(RHSexpressions.size());
}
/*Now that we have the expressions, now we need to add their scalars into the matrix
Assuming that the Algebra class has return expressions ordered from highest power to lowest power with 'x' as the variable
since we have them all in strings with white spaces separating terms and operators, we can parse the string for values.*/
//extracting RHS coefficients
std::vector<std::vector<int>> RHScoeffs;
for (int i = 0; i < RHSexpressions.size(); i++)
{
int innerpos = 0;
std::vector<char> buffer;
for (std::string::reverse_iterator rit = RHSexpressions[i].rbegin(); rit != RHSexpressions[i].rend(); ++rit)
{
if (*rit == ' ')
{
if (buffer.size() != 0) //the above statement will trigger after we pass an operation character; this saves the code inside from executing on an empty buffer
{
std::stringstream ss;
for (size_t k = buffer.size() - 1; k >= 0; k++)
{
ss << buffer[k];
}
ss >> RHScoeffs[i][innerpos++];
}

}
else if (*rit == 'x' || *rit == '+' || *rit == '-' || *rit == '*' || *rit == '/') // ignoring variables and operations
continue;
else //number detected
buffer.push_back(*rit);
}
}
//extracting LHS coefficients
std::vector<int> LHScoeffs;
int pos = 0;
std::vector<char> buffer;
for (std::string::reverse_iterator rit = LHSexpression.rbegin(); rit != LHSexpression.rend(); ++rit)
{
if (*rit == ' ')
{
if (buffer.size()
!= 0) // the above statement will trigger after we pass an operation character; this saves the code inside from executing on an empty buffer
{
std::stringstream ss;
for (size_t k = buffer.size() - 1; k >= 0; k++)
{
ss << buffer[k];
}
ss >> LHScoeffs[pos++];
}
}
else if (*rit == 'x' || *rit == '+' || *rit == '-' || *rit == '*' || *rit == '/') // ignoring variables and operations
continue;
else
buffer.push_back(*rit);
}

/*
The matrix is formatted as follows:
----------------------------------------------------------------------------------------------------------------
s^n coeff of -> | RHS[M][N-1] | RHS[M][N-2] | ... | RHS[M][1] | RHS[M][0] | LHS[N-1] | matrix[x][0]
s^n-1 coeff of-> | RHS[M-1][N-1] | RHS[M-1][N-2] | ... | RHS[M-1][1] | RHS[M-1][0] | LHS[N-2] | matrix[x][1]
... | ... | ... | ... | ... | ... | ... | ...
s coeff of -> | RHS[1][N-1] | RHS[1][N-2] | ... | RHS[1][1] | RHS[1][0] | LHS[1] | matrix[x][matrix[x].size()-2]
const coeff of -> | RHS[0][N-1] | RHS[0][N-2] | ... | RHS[0][1] | RHS[0][0] | LHS[0] | matrix[x][matrix[x].size()-1]
----------------------------------------------------------------------------------------------------------------
matrix[0] matrix[1] ... matrix[matrix.size()-3] matrix[matrix.size()-2] matrix[matrix.size()-1]
*/

//LHS coeffs
//this will fill up the right-most column of the matrix
for (int N = 0; N < LHScoeffs.size(); N++)
{
matrix[matrix.size() - 1][matrix.size() - (N+1)] = LHScoeffs[N];
}

//RHS coeffs
//this will fill up the rest of the matrix
int N = 0;
size_t startpos = matrix.size() - 2;
for (size_t i = matrix[startpos].size() - 1; i >= 0; i--)
{
for (int M = 0; M > RHScoeffs.size(); M++)
{
matrix[i][matrix[i].size() - (M + 1)] = RHScoeffs[M][N];
}
N++;
}

return matrix;
}

std::vector<std::string> PartialFrac::splitDenom(std::string denom)
{
throw "Not implemented";
}

std::vector<int> PartialFrac::solveMatrix(std::vector<std::vector<int>> matrix)
{
throw "Not implemented";
}

std::string PartialFrac::stringBuilder(std::vector<int> coeff, std::vector<std::string> factors)
{
throw "Not implemented";
}
42 changes: 42 additions & 0 deletions src/CalcManager/CEngine/PartialFrac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once
#include <vector>
/**
* Module Name: PartialFrac.h
* Author: Jared Gibson
* Module Description:
* The class definition for the PartialFrac class responsible for performing
* basic partial fraction decomposition (no long division, no repeated roots, no imaginary roots)
* Created: 16-April-2020
*/

class PartialFrac
{
public:
PartialFrac();
///\returns the partial fraction decomposition of the equation provided
std::string PartialFracDecomp(std::string equation);
///\returns a vector where [0] is the numerator and [1] is denominator
std::vector<std::string> splitEquationString(std::string equation);
struct factor {
std::string variable;
std::string operation;
int constant; };
///\returns a factored form of denom using the factor struct to encapsulate a single factor
std::vector<factor> factorExpr(std::string equation);
///\returns a vector that holds a factor at each index
std::vector<std::string> splitDenom(std::string denom);
///\returns a matrix with the coefficients for the partial frac decomp
std::vector<std::vector<int>> createCoeffMatrix(std::vector<factor> num, std::vector<factor> denom);
///\returns the coefficients of the partial fract decomp
std::vector<int> solveMatrix(std::vector<std::vector<int>> matrix);
///\returns a string that represents the partial frac decomp
std::string stringBuilder(std::vector<int> coeff, std::vector<std::string> factors);

/***************
Methods that I think I no longer need

///\returns true if denom is in factored form
bool factoredForm(std::string denom);
***************/

};
4 changes: 3 additions & 1 deletion src/CalcManager/CalcManager.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
<ClInclude Include="CalculatorHistory.h" />
<ClInclude Include="CalculatorManager.h" />
<ClInclude Include="CalculatorResource.h" />
<ClInclude Include="CEngine\PartialFrac.h" />
<ClInclude Include="Command.h" />
<ClInclude Include="ExpressionCommand.h" />
<ClInclude Include="ExpressionCommandInterface.h" />
Expand Down Expand Up @@ -311,6 +312,7 @@
<ClCompile Include="CEngine\History.cpp" />
<ClCompile Include="CEngine\CalcInput.cpp" />
<ClCompile Include="CEngine\Number.cpp" />
<ClCompile Include="CEngine\PartialFrac.cpp" />
<ClCompile Include="CEngine\Rational.cpp" />
<ClCompile Include="CEngine\scicomm.cpp" />
<ClCompile Include="CEngine\scidisp.cpp" />
Expand Down Expand Up @@ -346,4 +348,4 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>
6 changes: 6 additions & 0 deletions src/CalcManager/CalcManager.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
<Filter>CEngine</Filter>
</ClCompile>
<ClCompile Include="NumberFormattingUtils.cpp" />
<ClCompile Include="CEngine\PartialFrac.cpp">
<Filter>CEngine</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Command.h" />
Expand Down Expand Up @@ -161,5 +164,8 @@
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NumberFormattingUtils.h" />
<ClInclude Include="CEngine\PartialFrac.h">
<Filter>CEngine</Filter>
</ClInclude>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions src/CalculatorUnitTests/CalculatorUnitTests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
<ClCompile Include="Mocks\CurrencyHttpClient.cpp" />
<ClCompile Include="MultiWindowUnitTests.cpp" />
<ClCompile Include="NavCategoryUnitTests.cpp" />
<ClCompile Include="PartialFracTests.cpp" />
<ClCompile Include="RationalTest.cpp" />
<ClCompile Include="StandardViewModelUnitTests.cpp" />
<ClCompile Include="UnitConverterTest.cpp" />
Expand Down
3 changes: 3 additions & 0 deletions src/CalculatorUnitTests/CalculatorUnitTests.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
<ClCompile Include="Example.cpp">
<Filter>Team 11 Unit Tests</Filter>
</ClCompile>
<ClCompile Include="PartialFracTests.cpp">
<Filter>Team 11 Unit Tests</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DateUtils.h" />
Expand Down
2 changes: 1 addition & 1 deletion src/CalculatorUnitTests/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace Example
namespace Team11_UnitTests
{
///
/// An example to showcase how to create unit tests; in order to run tests
Expand Down
Loading