simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

util.js (8554B)


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