simplifyCore.js (7693B)
1 import { isAccessorNode, isArrayNode, isConstantNode, isFunctionNode, isIndexNode, isObjectNode, isOperatorNode } from '../../utils/is.js'; 2 import { createUtil } from './simplify/util.js'; 3 import { factory } from '../../utils/factory.js'; 4 var name = 'simplifyCore'; 5 var dependencies = ['equal', 'isZero', 'add', 'subtract', 'multiply', 'divide', 'pow', 'AccessorNode', 'ArrayNode', 'ConstantNode', 'FunctionNode', 'IndexNode', 'ObjectNode', 'OperatorNode', 'ParenthesisNode', 'SymbolNode']; 6 export var createSimplifyCore = /* #__PURE__ */factory(name, dependencies, _ref => { 7 var { 8 equal, 9 isZero, 10 add, 11 subtract, 12 multiply, 13 divide, 14 pow, 15 AccessorNode, 16 ArrayNode, 17 ConstantNode, 18 FunctionNode, 19 IndexNode, 20 ObjectNode, 21 OperatorNode, 22 ParenthesisNode, 23 SymbolNode 24 } = _ref; 25 var node0 = new ConstantNode(0); 26 var node1 = new ConstantNode(1); 27 var { 28 hasProperty, 29 isCommutative 30 } = createUtil({ 31 FunctionNode, 32 OperatorNode, 33 SymbolNode 34 }); 35 /** 36 * simplifyCore() performs single pass simplification suitable for 37 * applications requiring ultimate performance. In contrast, simplify() 38 * extends simplifyCore() with additional passes to provide deeper 39 * simplification. 40 * 41 * Syntax: 42 * 43 * simplifyCore(expr) 44 * 45 * Examples: 46 * 47 * const f = math.parse('2 * 1 * x ^ (2 - 1)') 48 * math.simpifyCore(f) // Node {2 * x} 49 * math.simplify('2 * 1 * x ^ (2 - 1)', [math.simplifyCore]) // Node {2 * x} 50 * 51 * See also: 52 * 53 * simplify, resolve, derivative 54 * 55 * @param {Node} node 56 * The expression to be simplified 57 * @param {Object} options 58 * Simplification options, as per simplify() 59 * @return {Node} Returns expression with basic simplifications applied 60 */ 61 62 function simplifyCore(node, options) { 63 var context = options ? options.context : undefined; 64 65 if (hasProperty(node, 'trivial', context)) { 66 // This node does nothing if it has only one argument, so if so, 67 // return that argument simplified 68 if (isFunctionNode(node) && node.args.length === 1) { 69 return simplifyCore(node.args[0], options); 70 } // For other node types, we try the generic methods 71 72 73 var simpChild = false; 74 var childCount = 0; 75 node.forEach(c => { 76 ++childCount; 77 78 if (childCount === 1) { 79 simpChild = simplifyCore(c, options); 80 } 81 }); 82 83 if (childCount === 1) { 84 return simpChild; 85 } 86 } 87 88 if (isOperatorNode(node) && node.isUnary()) { 89 var a0 = simplifyCore(node.args[0], options); 90 91 if (node.op === '-') { 92 // unary minus 93 if (isOperatorNode(a0)) { 94 if (a0.isUnary() && a0.op === '-') { 95 return a0.args[0]; 96 } else if (a0.isBinary() && a0.fn === 'subtract') { 97 return new OperatorNode('-', 'subtract', [a0.args[1], a0.args[0]]); 98 } 99 } 100 101 return new OperatorNode(node.op, node.fn, [a0]); 102 } 103 } else if (isOperatorNode(node) && node.isBinary()) { 104 var _a = simplifyCore(node.args[0], options); 105 106 var a1 = simplifyCore(node.args[1], options); 107 108 if (node.op === '+') { 109 if (isConstantNode(_a)) { 110 if (isZero(_a.value)) { 111 return a1; 112 } else if (isConstantNode(a1)) { 113 return new ConstantNode(add(_a.value, a1.value)); 114 } 115 } 116 117 if (isConstantNode(a1) && isZero(a1.value)) { 118 return _a; 119 } 120 121 if (isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { 122 return new OperatorNode('-', 'subtract', [_a, a1.args[0]]); 123 } 124 125 return new OperatorNode(node.op, node.fn, a1 ? [_a, a1] : [_a]); 126 } else if (node.op === '-') { 127 if (isConstantNode(_a) && a1) { 128 if (isConstantNode(a1)) { 129 return new ConstantNode(subtract(_a.value, a1.value)); 130 } else if (isZero(_a.value)) { 131 return new OperatorNode('-', 'unaryMinus', [a1]); 132 } 133 } // if (node.fn === "subtract" && node.args.length === 2) { 134 135 136 if (node.fn === 'subtract') { 137 if (isConstantNode(a1) && isZero(a1.value)) { 138 return _a; 139 } 140 141 if (isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { 142 return simplifyCore(new OperatorNode('+', 'add', [_a, a1.args[0]]), options); 143 } 144 145 return new OperatorNode(node.op, node.fn, [_a, a1]); 146 } 147 } else if (node.op === '*') { 148 if (isConstantNode(_a)) { 149 if (isZero(_a.value)) { 150 return node0; 151 } else if (equal(_a.value, 1)) { 152 return a1; 153 } else if (isConstantNode(a1)) { 154 return new ConstantNode(multiply(_a.value, a1.value)); 155 } 156 } 157 158 if (isConstantNode(a1)) { 159 if (isZero(a1.value)) { 160 return node0; 161 } else if (equal(a1.value, 1)) { 162 return _a; 163 } else if (isOperatorNode(_a) && _a.isBinary() && _a.op === node.op && isCommutative(node, context)) { 164 var a00 = _a.args[0]; 165 166 if (isConstantNode(a00)) { 167 var a00a1 = new ConstantNode(multiply(a00.value, a1.value)); 168 return new OperatorNode(node.op, node.fn, [a00a1, _a.args[1]], node.implicit); // constants on left 169 } 170 } 171 172 if (isCommutative(node, context)) { 173 return new OperatorNode(node.op, node.fn, [a1, _a], node.implicit); // constants on left 174 } else { 175 return new OperatorNode(node.op, node.fn, [_a, a1], node.implicit); 176 } 177 } 178 179 return new OperatorNode(node.op, node.fn, [_a, a1], node.implicit); 180 } else if (node.op === '/') { 181 if (isConstantNode(_a)) { 182 if (isZero(_a.value)) { 183 return node0; 184 } else if (isConstantNode(a1) && (equal(a1.value, 1) || equal(a1.value, 2) || equal(a1.value, 4))) { 185 return new ConstantNode(divide(_a.value, a1.value)); 186 } 187 } 188 189 return new OperatorNode(node.op, node.fn, [_a, a1]); 190 } else if (node.op === '^') { 191 if (isConstantNode(a1)) { 192 if (isZero(a1.value)) { 193 return node1; 194 } else if (equal(a1.value, 1)) { 195 return _a; 196 } else { 197 if (isConstantNode(_a)) { 198 // fold constant 199 return new ConstantNode(pow(_a.value, a1.value)); 200 } else if (isOperatorNode(_a) && _a.isBinary() && _a.op === '^') { 201 var a01 = _a.args[1]; 202 203 if (isConstantNode(a01)) { 204 return new OperatorNode(node.op, node.fn, [_a.args[0], new ConstantNode(multiply(a01.value, a1.value))]); 205 } 206 } 207 } 208 } 209 } 210 211 return new OperatorNode(node.op, node.fn, [_a, a1]); 212 } else if (isFunctionNode(node)) { 213 return new FunctionNode(simplifyCore(node.fn), node.args.map(n => simplifyCore(n, options))); 214 } else if (isArrayNode(node)) { 215 return new ArrayNode(node.items.map(n => simplifyCore(n, options))); 216 } else if (isAccessorNode(node)) { 217 return new AccessorNode(simplifyCore(node.object, options), simplifyCore(node.index, options)); 218 } else if (isIndexNode(node)) { 219 return new IndexNode(node.dimensions.map(n => simplifyCore(n, options))); 220 } else if (isObjectNode(node)) { 221 var newProps = {}; 222 223 for (var prop in node.properties) { 224 newProps[prop] = simplifyCore(node.properties[prop], options); 225 } 226 227 return new ObjectNode(newProps); 228 } else {// cannot simplify 229 } 230 231 return node; 232 } 233 234 return simplifyCore; 235 });