simple-squiggle

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

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 });