util.js 7.7 KB

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