-
Notifications
You must be signed in to change notification settings - Fork 276
Mathsteps organization
Simplification of a math expression is organized around a loop of searchers that look for rules to apply. Here's a handy gif that describes how mathsteps finds and applies the ▢⁰ => 1 rule:
You can read more about how this works in the Simplifying expressions math step-by-step section of our blog post.
Within /lib/simplifyExpression
, each folder represents a math searcher. /lib/simplifyExpression/arithmeticSearch
contains the modules related to searching and applying arithmetic rules when simplifying an expression.
The different types of searchers currently applied can be found in the stepThrough
module of simplifyExpression
, which manages the actual determination of the steps in simplifying an expression:
const simplificationTreeSearches = [
// Basic simplifications that we always try first e.g. (...)^0 => 1
basicsSearch,
// Simplify any division chains so there's at most one division operation.
// e.g. 2/x/6 -> 2/(x*6) e.g. 2/(x/6) => 2 * 6/x
divisionSearch,
// Adding fractions, cancelling out things in fractions
fractionsSearch,
// e.g. 2 + 2 => 4
arithmeticSearch,
// e.g. addition: 2x + 4x^2 + x => 4x^2 + 3x
// e.g. multiplication: 2x * x * x^2 => 2x^3
collectAndCombineSearch,
// e.g. (2 + x) / 4 => 2/4 + x/4
breakUpNumeratorSearch,
// e.g. 3/x * 2x/5 => (3 * 2x) / (x * 5)
multiplyFractionsSearch,
// e.g. (2x + 3)(x + 4) => 2x^2 + 11x + 12
distributeSearch,
// e.g. abs(-4) => 4
functionsSearch,
];
We group similar rules together in a single searcher. basicSearch
for example contains many simple rules such as the aforementioned simplification of anything to the power to 0 is just 1 and anything multiplied by 1 is just itself.
Most new expression simplification rules can fit in one of these searchers, but we also look forward to adding new types of searchers.
Within each searcher module, will be an index.js
file that defines a the type of search (pre- or post- order) and the function to apply for that search. A great example is breakUpNumeratorSearch
.
The Node module defines functionality to deal with the Node objects that represent mathematical expressions within mathsteps. This includes /lib/node/Creator.js
which deals with creating new nodes, /lib/node/Polynomial.js
which handles the abstraction of polynomial term nodes, and the NodeStatus object defined in /lib/node/Status.js
which represents a node's status during any given simplification step.
The architecture for solving an equation is similar to that of of simplifying an expression, but only operates a single set of rules, all related to isolating the variable which we are solving for. These rules are similarly in the /lib/solveEquation/stepThrough.js
:
// ensure the symbol is always on the left node
EquationOperations.ensureSymbolInLeftNode,
// get rid of denominators that have the symbol
EquationOperations.removeSymbolFromDenominator,
// remove the symbol from the right side
EquationOperations.removeSymbolFromRightSide,
// isolate the symbol on the left side
EquationOperations.isolateSymbolOnLeftSide,
Each of these operations is currently defined in /lib/solveEquation/EquationOperations.js
.
The equation module defines functionality related to equations, includes the Equation
object, which stores a left side, right side and a comparator that defines the equation, and the EquationStatus
object which represents the status of an equation during a solution step.
Checks related to simplifying or solving an equation, for example whether one can add like term polynomials in an expression, are all in the /lib/checks
directory.
Code related to factoring a polynomial or a constant into it's primes is stored in the /lib/factor
directory. Factoring is distinct from solving or simplifying and so it is a top-level directory within lib.
We aim to have complete test coverage of the codebase. Tests for each module are located under the /test directory, in the same structure as found in /lib.