Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
Expressions with polynomials divided by polynomials are now simplified (
Browse files Browse the repository at this point in the history
#231)

* Expressions with polynomials divided by polynomials are now simplified

* minor naming/style changes

* minor thought fail fix
  • Loading branch information
marpol2 authored and evykassirer committed Jan 17, 2018
1 parent 2c481db commit e5a69b7
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
54 changes: 49 additions & 5 deletions lib/simplifyExpression/fractionsSearch/cancelLikeTerms.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ function cancelTerms(numerator, denominator) {
if (print.ascii(numerator) === print.ascii(denominator)) {
return new CancelOutStatus(null, null, true);
}

// case 2: they're both exponent nodes with the same base
// e.g. (2x+5)^8 and (2x+5)^2
if (Node.Type.isOperator(numerator, '^') &&
Expand All @@ -257,16 +256,25 @@ function cancelTerms(numerator, denominator) {
numerator.args[1] = newExponent;
return new CancelOutStatus(numerator, null, true);
}

// case 3: they're both polynomial terms, check if they have the same symbol
// e.g. 4x^2 / 5x^2 => 4 / 5
// e.g. 4x^3 / 5x^2 => 4x^(3-2) / 5
// case 3.1: they're both polynomial terms with different symbols but with coefficients
// e.g 20x / 40y => x / 2y
// e.g 60x / 40y => 3x / 2y
// e.g 4x / 2y => 2x / y
if (Node.PolynomialTerm.isPolynomialTerm(numerator) &&
Node.PolynomialTerm.isPolynomialTerm(denominator)) {
const numeratorTerm = new Node.PolynomialTerm(numerator);
const denominatorTerm = new Node.PolynomialTerm(denominator);
if (numeratorTerm.getSymbolName() !== denominatorTerm.getSymbolName()) {
return new CancelOutStatus(numerator, denominator);
if (Node.Type.isOperator(numerator, '*') && Node.Type.isOperator(denominator, '*')) {
// case 3.1
return cancelCoeffs(numerator, denominator);
}
else {
return new CancelOutStatus(numerator, denominator);
}
}
const numeratorExponent = numeratorTerm.getExponentNode(true);
let denominatorExponent = denominatorTerm.getExponentNode(true);
Expand Down Expand Up @@ -294,7 +302,6 @@ function cancelTerms(numerator, denominator) {
// or is multiplication node
// e.g. 2 / 4x -> 1 / 2x
// e.g. ignore cases like: 2 / a and 2 / x^2

if (Node.Type.isConstant(numerator)
&& Node.Type.isOperator(denominator, '*')
&& Node.PolynomialTerm.isPolynomialTerm(denominator)) {
Expand Down Expand Up @@ -330,7 +337,6 @@ function cancelTerms(numerator, denominator) {

// case 5: both numerator and denominator are numbers within a more complicated fraction
// e.g. (35 * nthRoot (7)) / (5 * nthRoot(5)) -> (7 * nthRoot(7)) / nthRoot(5)

if (Node.Type.isConstant(numerator) && Node.Type.isConstant(denominator)) {
const frac = Node.Creator.operator('/', [numerator, denominator]);
const reduceStatus = divideByGCD(frac);
Expand Down Expand Up @@ -371,4 +377,42 @@ function isMultiplicationOfTerms(node) {
!Node.PolynomialTerm.isPolynomialTerm(node));
}

function cancelCoeffs(numerator, denominator){
const denominatorTerm = new Node.PolynomialTerm(denominator);
const numeratorTerm = new Node.PolynomialTerm(numerator);

const denominatorCoeff = denominatorTerm.getCoeffNode();
const denominatorVariable = denominatorTerm.getSymbolNode();
const denominatorExponent = denominatorTerm.getExponentNode();

const numeratorCoeff = numeratorTerm.getCoeffNode();
const numeratorVariable = numeratorTerm.getSymbolNode();
const numeratorExponent = numeratorTerm.getExponentNode();

// simplify a constant fraction (e.g 2 / 4)
const frac = Node.Creator.operator('/', [numeratorCoeff, denominatorCoeff]);

const reduceStatus = divideByGCD(frac);

if (!reduceStatus.hasChanged()) {
return new CancelOutStatus(numerator, denominator, false);
}

// Sometimes the fraction reduces to a constant e.g. 6 / 2 -> 3,
// in which case the denominator coefficient should be null
let newDenominatorCoeff = null;
let newNumerator = null;
if (Node.Type.isConstant(reduceStatus.newNode)) {
newNumerator = Node.Creator.polynomialTerm(numeratorVariable, numeratorExponent, reduceStatus.newNode);
newDenominatorCoeff = null;
}
else {
newNumerator = Node.Creator.polynomialTerm(numeratorVariable, numeratorExponent, reduceStatus.newNode.args[0]);
newDenominatorCoeff = reduceStatus.newNode.args[1];
}
const newDenominator = Node.Creator.polynomialTerm(denominatorVariable, denominatorExponent, newDenominatorCoeff);

return new CancelOutStatus(newNumerator, newDenominator, true);
}

module.exports = cancelLikeTerms;
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ describe('cancel like terms', function () {
['2/ (4x)', '1 / (2x)'],
['2/ (4x^2)', '1 / (2x^2)'],
['2 a / a', '2'],
['(35 * nthRoot (7)) / (5 * nthRoot(5))','(7 * nthRoot(7)) / nthRoot(5)'],
['(35 * nthRoot (7)) / (5 * nthRoot(5))', '(7 * nthRoot(7)) / nthRoot(5)'],
['3/(9r^2)', '1 / (3r^2)'],
['6/(2x)', '3 / (x)']
['6/(2x)', '3 / (x)'],
['(40 * x) / (20 * y)', '(2x) / (y)'],
['(20 * x) / (40 * y)', '(x) / (2y)'],
['20x / (40y)', 'x / (2y)'],
['60x / (40y)', '3x / (2y)'],
['4x / (2y)', '2x / (y)']
];

tests.forEach(t => testCancelLikeTerms(t[0], t[1]));
Expand Down
5 changes: 5 additions & 0 deletions test/simplifyExpression/simplify.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ describe('can simplify with division', function () {
['2x/x', '2'],
['2x/4/3', '1/6 x'],
['((2+x)(3+x))/(2+x)', '3 + x'],
['(20 * x) / (5 * (40 * y))', 'x / (10y)'],
['400 * z / ((20 * x) / (5 * (40 * y)))', '(4000y * z) / x'],
['20x / (40y)', 'x / (2y)'],
['60x / (40y)', '3x / (2y)'],
['4x / (2y)', '2x / y']
];
tests.forEach(t => testSimplify(t[0], t[1], t[2]));
// TODO: factor the numerator to cancel out with denominator
Expand Down

0 comments on commit e5a69b7

Please sign in to comment.