Skip to content

Commit 605b31e

Browse files
committed
adding an index.js file for factoring and exposing it to top level of the mathsteps module
1 parent 1bfe30e commit 605b31e

File tree

7 files changed

+96
-9
lines changed

7 files changed

+96
-9
lines changed

index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const ChangeTypes = require('./lib/ChangeTypes');
2+
const factor = require('./lib/factor');
23
const simplifyExpression = require('./lib/simplifyExpression');
34
const solveEquation = require('./lib/solveEquation');
45

56
module.exports = {
7+
factor,
68
simplifyExpression,
79
solveEquation,
810
ChangeTypes,

lib/factor/factorQuadratic.js

-7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ const math = require('mathjs');
33
const ConstantFactors = require('./ConstantFactors');
44

55
const ChangeTypes = require('../ChangeTypes');
6-
const checks = require('../checks');
76
const evaluate = require('../util/evaluate');
8-
const flatten = require('../util/flattenOperands');
97
const Negative = require('../Negative');
108
const Node = require('../node');
119

@@ -31,11 +29,6 @@ const FACTOR_FUNCTIONS = [
3129
// requires us simplify the following only within the parens:
3230
// a(x - (-b + sqrt(b^2 - 4ac)) / 2a)(x - (-b - sqrt(b^2 - 4ac)) / 2a)
3331
function factorQuadratic(node) {
34-
node = flatten(node);
35-
if (!checks.isQuadratic(node)) {
36-
return Node.Status.noChange(node);
37-
}
38-
3932
// get a, b and c
4033
let symbol, aValue = 0, bValue = 0, cValue = 0;
4134
for (const term of node.args) {

lib/factor/index.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const math = require('mathjs');
2+
const stepThrough = require('./stepThrough');
3+
4+
function factorString(expressionString, debug=false) {
5+
let node;
6+
try {
7+
node = math.parse(expressionString);
8+
}
9+
catch (err) {
10+
return [];
11+
}
12+
13+
if (node) {
14+
return stepThrough(node, debug);
15+
}
16+
return [];
17+
}
18+
19+
module.exports = factorString;

lib/factor/stepThrough.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const checks = require('../checks');
2+
3+
const factorQuadratic = require('./factorQuadratic');
4+
5+
const flattenOperands = require('../util/flattenOperands');
6+
const removeUnnecessaryParens = require('../util/removeUnnecessaryParens');
7+
8+
// Given a mathjs expression node, steps through factoring the expression.
9+
// Currently only supports factoring quadratics.
10+
// Returns a list of details about each step.
11+
function stepThrough(node, debug=false) {
12+
if (debug) {
13+
// eslint-disable-next-line
14+
console.log('\n\nFactoring: ' + print(node, false, true));
15+
}
16+
17+
if (checks.hasUnsupportedNodes(node)) {
18+
return [];
19+
}
20+
21+
let nodeStatus;
22+
const steps = [];
23+
24+
node = flattenOperands(node);
25+
node = removeUnnecessaryParens(node, true);
26+
if (checks.isQuadratic(node)) {
27+
nodeStatus = factorQuadratic(node);
28+
if (nodeStatus.hasChanged()) {
29+
steps.push(nodeStatus);
30+
}
31+
}
32+
// Add factoring higher order polynomials...
33+
34+
return steps;
35+
}
36+
37+
module.exports = stepThrough;

lib/simplifyExpression/stepThrough.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ function stepThrough(node, debug=false) {
4343
logSteps(nodeStatus);
4444
}
4545
steps.push(removeUnnecessaryParensInStep(nodeStatus));
46-
const nextNode = Status.resetChangeGroups(nodeStatus.newNode);
47-
nodeStatus = step(nextNode);
46+
47+
node = Status.resetChangeGroups(nodeStatus.newNode);
48+
nodeStatus = step(node);
49+
4850
if (iters++ === MAX_STEP_COUNT) {
4951
// eslint-disable-next-line
5052
console.error('Math error: Potential infinite loop for expression: ' +

test/factor/factor.test.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const assert = require('assert');
2+
const factor = require('../../lib/factor');
3+
const print = require('../../lib/util/print');
4+
5+
const NO_STEPS = 'no-steps';
6+
7+
function testFactor(expressionString, outputStr, debug=false) {
8+
const steps = factor(expressionString, debug);
9+
let lastStep;
10+
if (steps.length === 0) {
11+
lastStep = NO_STEPS;
12+
}
13+
else {
14+
lastStep = print(steps[steps.length -1].newNode);
15+
}
16+
it(expressionString + ' -> ' + outputStr, (done) => {
17+
assert.equal(lastStep, outputStr);
18+
done();
19+
});
20+
}
21+
22+
describe('factor expressions', function () {
23+
const tests = [
24+
['x^2', NO_STEPS],
25+
['x^2 + 2x', 'x * (x + 2)'],
26+
['x^2 - 4', '(x + 2) * (x - 2)'],
27+
['x^2 + 4', NO_STEPS],
28+
['x^2 + 2x + 1', '(x + 1)^2'],
29+
['x^2 + 3x + 2', '(x + 1) * (x + 2)'],
30+
];
31+
tests.forEach(t => testFactor(t[0], t[1], t[2]));
32+
});
33+

test/factor/factorQuadratic.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('factorQuadratic', function () {
2929
['-x^2 - 3x - 2', '-(x + 1) * (x + 2)'],
3030
['-x^2 + 1', '-(x + 1) * (x - 1)'],
3131
['-x^2 - 1', '-x^2 - 1'],
32+
//['2x^2 + 5x + 3','(x + 3) * (2x - 1)'], // TODO(ael)
3233
];
3334
tests.forEach(t => testFactorQuadratic(t[0], t[1]));
3435
});

0 commit comments

Comments
 (0)