UNPKG

mathsteps-experimental-fork

Version:

Step by step math solutions. Experimental Fork

131 lines (128 loc) 6.5 kB
import math from '../index.js'; import { myNodeToString } from './nodeServices/myNodeToString.js'; import { parseText } from './nodeServices/parseText.js'; import { removeUnnecessaryParentheses } from './nodeServices/removeUnnessaryParenthesis.js'; import { removeImplicitMultiplicationFromNode } from './treeUtil.js'; import { kemuFlatten, kemuNormalizeConstantNodes } from '../simplifyExpression/kemuSimplifyCommonServices.js'; import { convertNumParVarDivNumToNumVarDivNum, convertAll1xToX, convertAllSimpleFractionsToDecimals, normalizeNegativesAndFractions, makePlusMinusMinusAndReturnString } from '../simplifyExpression/mscNormalizeNodeFunctions.js'; import { areArraysEqualUnordered } from '../util/arrayUtils.js'; import { cleanString } from '../util/cleanString.js'; import { RGFraction, makeExtendedRegExp } from '../util/regex.js'; import _kemuSortArgs from '../simplifyExpression/kemuSortArgs.js'; const getNodeStepsToSolveExpression = (userStep) => math.simplifyExpression({ expressionAsText: cleanString(userStep), isDebugMode: false, expressionCtx: void 0, getMistakes: false, getAllNextStepPossibilities: false, onStepCb: (step) => { } }); function normalizeNodeForEquality(node_) { let node = typeof node_ === "string" ? parseText(node_) : node_; node = convertNumParVarDivNumToNumVarDivNum(node); node = removeUnnecessaryParentheses(node); node = convertAll1xToX(node); node = kemuFlatten(node); node = removeImplicitMultiplicationFromNode(node); node = convertAllSimpleFractionsToDecimals(node); node = normalizeNegativesAndFractions(node); node = kemuNormalizeConstantNodes(node); node = convertAll1xToX(node); node = _kemuSortArgs(node, true, true); return node; } function normalizeStringExpressionForEquality(stringExpression) { stringExpression = cleanString(stringExpression); stringExpression = stringExpression.replace(/\((\d+(\.\d+)?)\)/g, "$1"); stringExpression = stringExpression.replace(/\(-(\d+(\.\d+)?)\)/g, "-$1"); stringExpression = makePlusMinusMinusAndReturnString(`0+${stringExpression}`); stringExpression = stringExpression.replaceAll(/\b0[a-z]\b/gi, "0"); stringExpression = stringExpression.replaceAll(/\b1([a-z])\b/gi, "$1"); stringExpression = stringExpression.replace(/(\d+)\*([a-z])/gi, "$1$2"); const numberRG = "\\b\\d+(?:\\.\\d+)?[a-z]?\\b"; const regexExp = makeExtendedRegExp(String.raw`\b(${numberRG})-\((${numberRG})/(${numberRG})\)`, "gi"); stringExpression = stringExpression.replace(regexExp, "$1+(-$2/$3)"); stringExpression = cleanString(stringExpression); return stringExpression; } function areEquationsEqual(eq0, eq1, equalityCache = null) { const sides0 = eq0.split("=").map((side) => cleanString(side)); const sides1 = eq1.split("=").map((side) => cleanString(side)); return areExpressionEqual(sides0[0], sides1[0], equalityCache) && areExpressionEqual(sides0[1], sides1[1], equalityCache); } function areExpressionEqual(exp0, exp1, equalityCache = null) { if (!exp0 || !exp1) return false; if (exp0 === exp1) return true; if (!equalityCache) { return areExpressionEqualCore(exp0, exp1); } else { const strExp0 = typeof exp0 === "string" ? cleanString(exp0) : myNodeToString(exp0); const strExp1 = typeof exp1 === "string" ? cleanString(exp1) : myNodeToString(exp1); return equalityCache.getCachedEquality(strExp0, strExp1, areExpressionEqualCore); } } function areExpressionEqualCore(exp0, exp1) { if (!exp0 || !exp1) return false; if (exp0 === exp1) return true; const strExp0 = typeof exp0 === "string" ? cleanString(exp0) : myNodeToString(exp0); const strExp1 = typeof exp1 === "string" ? cleanString(exp1) : myNodeToString(exp1); if (strExp0 === strExp1) return true; const normalizedExprString0 = normalizeStringExpressionForEquality(strExp0); const normalizedExprString1 = normalizeStringExpressionForEquality(strExp1); if (normalizedExprString0 === normalizedExprString1) return true; if (canDoEqualityBasedOnEventualAnswer(normalizedExprString0, normalizedExprString1)) { const answer1 = myNodeToString(getNodeStepsToSolveExpression(normalizedExprString0)); const answer2 = myNodeToString(getNodeStepsToSolveExpression(normalizedExprString1)); if (answer1 === answer2) return true; const normalizedAnswer1 = normalizeStringExpressionForEquality(answer1); const normalizedAnswer2 = normalizeStringExpressionForEquality(answer2); if (normalizedAnswer1 === normalizedAnswer2) return true; const normalizedAnswerNode0 = normalizeNodeForEquality(parseText(normalizedAnswer1)); const normalizedAnswerNode1 = normalizeNodeForEquality(parseText(normalizedAnswer2)); return normalizedAnswerNode0.equals(normalizedAnswerNode1); } else { const normalizedNode0 = normalizeNodeForEquality(parseText(normalizedExprString0)); const normalizedNode1 = normalizeNodeForEquality(parseText(normalizedExprString1)); return normalizedNode0.equals(normalizedNode1); } } function canDoEqualityBasedOnEventualAnswer(strExp0, strExp1) { const countMult0 = (strExp0.match(/\*/g) || []).length; const countMult1 = (strExp1.match(/\*/g) || []).length; if (countMult0 !== countMult1) return false; const countDiv0 = (strExp0.match(/\//g) || []).length; const countDiv1 = (strExp1.match(/\//g) || []).length; if (countDiv0 !== countDiv1) return false; if (strExp0.includes("/")) { const fractions0 = strExp0.match(RGFraction) || []; const fractions1 = strExp1.match(RGFraction) || []; if (!areArraysEqualUnordered(fractions0, fractions1, { isEqualFn: (a, b) => a === b })) return false; } const operators = ["+", "-", "*", "/"]; operators.forEach((op) => { strExp0 = strExp0.replaceAll(op, ` ${op} `); strExp1 = strExp1.replaceAll(op, ` ${op} `); }); strExp0 = strExp0.replace(/\s+/g, " "); strExp1 = strExp1.replace(/\s+/g, " "); strExp0 = strExp0.replaceAll("(", "").replaceAll(")", ""); strExp1 = strExp1.replaceAll("(", "").replaceAll(")", ""); strExp0 = strExp0.replaceAll("+", " ").replaceAll("-", " "); strExp1 = strExp1.replaceAll("+", " ").replaceAll("-", " "); const sortedStrExp0 = strExp0.split(/\s+/).sort().join("$"); const sortedStrExp1 = strExp1.split(/\s+/).sort().join("$"); return sortedStrExp0 === sortedStrExp1; } export { areEquationsEqual, areExpressionEqual, getNodeStepsToSolveExpression, normalizeNodeForEquality, normalizeStringExpressionForEquality };