util.js (7952B)
1 import _defineProperty from "@babel/runtime/helpers/defineProperty"; 2 3 function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } 4 5 function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } 6 7 import { isFunctionNode, isOperatorNode, isParenthesisNode } from '../../../utils/is.js'; 8 import { factory } from '../../../utils/factory.js'; 9 import { hasOwnProperty } from '../../../utils/object.js'; 10 var name = 'simplifyUtil'; 11 var dependencies = ['FunctionNode', 'OperatorNode', 'SymbolNode']; 12 export var createUtil = /* #__PURE__ */factory(name, dependencies, _ref => { 13 var { 14 FunctionNode, 15 OperatorNode, 16 SymbolNode 17 } = _ref; 18 // TODO commutative/associative properties rely on the arguments 19 // e.g. multiply is not commutative for matrices 20 // The properties should be calculated from an argument to simplify, or possibly something in math.config 21 // the other option is for typed() to specify a return type so that we can evaluate the type of arguments 22 23 /* So that properties of an operator fit on one line: */ 24 var T = true; 25 var F = false; 26 var defaultName = 'defaultF'; 27 var defaultContext = { 28 /* */ 29 add: { 30 trivial: T, 31 total: T, 32 commutative: T, 33 associative: T 34 }, 35 36 /**/ 37 unaryPlus: { 38 trivial: T, 39 total: T, 40 commutative: T, 41 associative: T 42 }, 43 44 /* */ 45 subtract: { 46 trivial: F, 47 total: T, 48 commutative: F, 49 associative: F 50 }, 51 52 /* */ 53 multiply: { 54 trivial: T, 55 total: T, 56 commutative: T, 57 associative: T 58 }, 59 60 /* */ 61 divide: { 62 trivial: F, 63 total: T, 64 commutative: F, 65 associative: F 66 }, 67 68 /* */ 69 paren: { 70 trivial: T, 71 total: T, 72 commutative: T, 73 associative: F 74 }, 75 76 /* */ 77 defaultF: { 78 trivial: F, 79 total: T, 80 commutative: F, 81 associative: F 82 } 83 }; 84 var realContext = { 85 divide: { 86 total: F 87 }, 88 log: { 89 total: F 90 } 91 }; 92 var positiveContext = { 93 subtract: { 94 total: F 95 }, 96 abs: { 97 trivial: T 98 }, 99 log: { 100 total: T 101 } 102 }; 103 104 function hasProperty(nodeOrName, property) { 105 var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultContext; 106 var name = defaultName; 107 108 if (typeof nodeOrName === 'string') { 109 name = nodeOrName; 110 } else if (isOperatorNode(nodeOrName)) { 111 name = nodeOrName.fn.toString(); 112 } else if (isFunctionNode(nodeOrName)) { 113 name = nodeOrName.name; 114 } else if (isParenthesisNode(nodeOrName)) { 115 name = 'paren'; 116 } 117 118 if (hasOwnProperty(context, name)) { 119 var properties = context[name]; 120 121 if (hasOwnProperty(properties, property)) { 122 return properties[property]; 123 } 124 125 if (hasOwnProperty(defaultContext, name)) { 126 return defaultContext[name][property]; 127 } 128 } 129 130 if (hasOwnProperty(context, defaultName)) { 131 var _properties = context[defaultName]; 132 133 if (hasOwnProperty(_properties, property)) { 134 return _properties[property]; 135 } 136 137 return defaultContext[defaultName][property]; 138 } 139 /* name not found in context and context has no global default */ 140 141 /* So use default context. */ 142 143 144 if (hasOwnProperty(defaultContext, name)) { 145 var _properties2 = defaultContext[name]; 146 147 if (hasOwnProperty(_properties2, property)) { 148 return _properties2[property]; 149 } 150 } 151 152 return defaultContext[defaultName][property]; 153 } 154 155 function isCommutative(node) { 156 var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultContext; 157 return hasProperty(node, 'commutative', context); 158 } 159 160 function isAssociative(node) { 161 var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultContext; 162 return hasProperty(node, 'associative', context); 163 } 164 /** 165 * Merge the given contexts, with primary overriding secondary 166 * wherever they might conflict 167 */ 168 169 170 function mergeContext(primary, secondary) { 171 var merged = _objectSpread({}, primary); 172 173 for (var prop in secondary) { 174 if (hasOwnProperty(primary, prop)) { 175 merged[prop] = _objectSpread(_objectSpread({}, secondary[prop]), primary[prop]); 176 } else { 177 merged[prop] = secondary[prop]; 178 } 179 } 180 181 return merged; 182 } 183 /** 184 * Flatten all associative operators in an expression tree. 185 * Assumes parentheses have already been removed. 186 */ 187 188 189 function flatten(node, context) { 190 if (!node.args || node.args.length === 0) { 191 return node; 192 } 193 194 node.args = allChildren(node, context); 195 196 for (var i = 0; i < node.args.length; i++) { 197 flatten(node.args[i], context); 198 } 199 } 200 /** 201 * Get the children of a node as if it has been flattened. 202 * TODO implement for FunctionNodes 203 */ 204 205 206 function allChildren(node, context) { 207 var op; 208 var children = []; 209 210 var findChildren = function findChildren(node) { 211 for (var i = 0; i < node.args.length; i++) { 212 var child = node.args[i]; 213 214 if (isOperatorNode(child) && op === child.op) { 215 findChildren(child); 216 } else { 217 children.push(child); 218 } 219 } 220 }; 221 222 if (isAssociative(node, context)) { 223 op = node.op; 224 findChildren(node); 225 return children; 226 } else { 227 return node.args; 228 } 229 } 230 /** 231 * Unflatten all flattened operators to a right-heavy binary tree. 232 */ 233 234 235 function unflattenr(node, context) { 236 if (!node.args || node.args.length === 0) { 237 return; 238 } 239 240 var makeNode = createMakeNodeFunction(node); 241 var l = node.args.length; 242 243 for (var i = 0; i < l; i++) { 244 unflattenr(node.args[i], context); 245 } 246 247 if (l > 2 && isAssociative(node, context)) { 248 var curnode = node.args.pop(); 249 250 while (node.args.length > 0) { 251 curnode = makeNode([node.args.pop(), curnode]); 252 } 253 254 node.args = curnode.args; 255 } 256 } 257 /** 258 * Unflatten all flattened operators to a left-heavy binary tree. 259 */ 260 261 262 function unflattenl(node, context) { 263 if (!node.args || node.args.length === 0) { 264 return; 265 } 266 267 var makeNode = createMakeNodeFunction(node); 268 var l = node.args.length; 269 270 for (var i = 0; i < l; i++) { 271 unflattenl(node.args[i], context); 272 } 273 274 if (l > 2 && isAssociative(node, context)) { 275 var curnode = node.args.shift(); 276 277 while (node.args.length > 0) { 278 curnode = makeNode([curnode, node.args.shift()]); 279 } 280 281 node.args = curnode.args; 282 } 283 } 284 285 function createMakeNodeFunction(node) { 286 if (isOperatorNode(node)) { 287 return function (args) { 288 try { 289 return new OperatorNode(node.op, node.fn, args, node.implicit); 290 } catch (err) { 291 console.error(err); 292 return []; 293 } 294 }; 295 } else { 296 return function (args) { 297 return new FunctionNode(new SymbolNode(node.name), args); 298 }; 299 } 300 } 301 302 return { 303 createMakeNodeFunction, 304 hasProperty, 305 isCommutative, 306 isAssociative, 307 mergeContext, 308 flatten, 309 allChildren, 310 unflattenr, 311 unflattenl, 312 defaultContext, 313 realContext, 314 positiveContext 315 }; 316 });