lib/util/flattenOperands.js
// Output: the expression tree updated with flattened operations
the expression tree updated with flattened operations
the expression tree updated with flattened operations
function flattenOperands(node) {
  if (Node.MixedNumber.isMixedNumber(node)) {
    return node;
  }
  if (Node.Type.isConstant(node, true)) {
    const constNode = Node.Creator.constant(evaluate(node));
    if (node.changeGroup) {
      constNode.changeGroup = node.changeGroup;
    }
    return constNode;
  }
  else if (Node.Type.isOperator(node)) {
    if ('+-/*'.includes(node.op)) {
      let parentOp;
      if (node.op === '/') {
        parentOp = '*';
      }
      else if (node.op === '-') {
        parentOp = '+';
      }
      else {
        parentOp = node.op;
      }
      return flattenSupportedOperation(node, parentOp);
    }
    else {
      node.args.forEach((child, i) => {
        node.args[i] = flattenOperands(child);
      });
    }
    return node;
  }
  else if (Node.Type.isParenthesis(node)) {
    node.content = flattenOperands(node.content);
    return node;
  }
  else if (Node.Type.isUnaryMinus(node)) {
    const arg = flattenOperands(node.args[0]);
    const flattenedNode = Negative.negate(arg, true);
    if (node.changeGroup) {
      flattenedNode.changeGroup = node.changeGroup;
    }
    return flattenedNode;
  }
  else if (Node.Type.isFunction(node) && node.fn.args) {
    const flattenedFn = flattenOperands(node.fn); 
    const flattenedArg = flattenOperands(node.args[0]); 
    const newNode = Node.Creator.operator(
      '*', [flattenedFn, Node.Creator.parenthesis(flattenedArg)]);
    return newNode;
  }
  else if (Node.Type.isFunction(node, 'abs')) {
    node.args[0] = flattenOperands(node.args[0]);
    return node;
  }
  else if (Node.Type.isFunction(node, 'nthRoot')) {
    node.args[0] = flattenOperands(node.args[0]);
    if (node.args[1]) {
      node.args[1] = flattenOperands(node.args[1]);
    }
    return node;
  }
  else {
    return node;
  }
}
function flattenOperands ( node ) { if ( Node . MixedNumber . isMixedNumber ( node ) ) { return node ; } if ( Node . Type . isConstant ( node , true ) ) { const constNode = Node . Creator . constant ( evaluate ( node ) ) ; if ( node . changeGroup ) { constNode . changeGroup = node . changeGroup ; } return constNode ; } else if ( Node . Type . isOperator ( node ) ) { if ( '+-/*' . includes ( node . op ) ) { let parentOp ; if ( node . op === '/' ) { parentOp = '*' ; } else if ( node . op === '-' ) { parentOp = '+' ; } else { parentOp = node . op ; } return flattenSupportedOperation ( node , parentOp ) ; } else { node . args . forEach ( ( child , i ) => { node . args [ i ] = flattenOperands ( child ) ; } ) ; } return node ; } else if ( Node . Type . isParenthesis ( node ) ) { node . content = flattenOperands ( node . content ) ; return node ; } else if ( Node . Type . isUnaryMinus ( node ) ) { const arg = flattenOperands ( node . args [ 0 ] ) ; const flattenedNode = Negative . negate ( arg , true ) ; if ( node . changeGroup ) { flattenedNode . changeGroup = node . changeGroup ; } return flattenedNode ; } else if ( Node . Type . isFunction ( node ) && node . fn . args ) { const flattenedFn = flattenOperands ( node . fn ) ; const flattenedArg = flattenOperands ( node . args [ 0 ] ) ; const newNode = Node . Creator . operator ( '*' , [ flattenedFn , Node . Creator . parenthesis ( flattenedArg ) ] ) ; return newNode ; } else if ( Node . Type . isFunction ( node , 'abs' ) ) { node . args [ 0 ] = flattenOperands ( node . args [ 0 ] ) ; return node ; } else if ( Node . Type . isFunction ( node , 'nthRoot' ) ) { node . args [ 0 ] = flattenOperands ( node . args [ 0 ] ) ; if ( node . args [ 1 ] ) { node . args [ 1 ] = flattenOperands ( node . args [ 1 ] ) ; } return node ; } else { return node ; } }
Output: the expression tree updated with flattened operations
Output : the expression tree updated with flattened operations
// If the node is a mixed number, do not perform any flattening // -- Flattening will take out the implicit multiplication, and so //    it will be impossible to tell if the node is a mixed number or //    if it is legitimate multiplication // -- Converting fractions happens before any other simplification step, //    so the tree *will* get flattened before any other changes happen // the evaluate() changes unary minuses around constant nodes to constant nodes // with negative values. // Division is flattened in partner with multiplication. This means // that after collecting the operands, they'll be children args of * // Subtraction is flattened in partner with addition, This means that // after collecting the operands, they'll be children args of + // If the operation is not supported, just recurse on the children // node.fn.args will only be populated in the case where a function node is // followed by a node in parenthesis // mathjs parses this incorrectly; we want to convert the node to be // multiplication between the function and the node in parenthesis // e.g. nthRoot(11)(x+y) -> nthRoot(11) * (x+y) //      abs(3)(1+2) -> abs(3) * (1+2) // e.g. nthRoot(11) // e.g. x+y