util.js 8.3 KB

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