Symbolic differentiation of prefix expressions

    0

    0

    const DEBUG = false ;
    
    const diff = expr => show(optimise(evaluate(parse(tokenise(expr))))) ;
    
    const tokenise = expression => DEBUG && console.log("<hr>tokenise",expression) ||
      ( expression.match( /-?(\d*\.)?\d+|\w+|[-+/*^]/g ) || [] ).map( t => isNumber(t) ? Number(t) : t )
    ;
    
    const parse = tokens => { DEBUG && console.log("<hr>parse",tokens);
      const doOp = (op,left,right) => new Node(op,left,right) ;
      const accept = s => [...s].some( v => v===tokens[0] ) && tokens.shift();
      const variable = () => doOp(tokens.shift()) ;
      const constant = () => isNumber(tokens[0]) ? tokens.shift() : variable() ;
      const binary = (op) => ( op = accept(BINARY) ) ? doOp(op,expr(),expr()) : constant() ;
      const expr = (op) => ( op = accept(UNARY) ) ? doOp(op,expr()) : binary() ;
      return expr();
    };
    
    const evaluate = node => DEBUG && console.log("<hr>evaluate",show(node)) ||
      isNumber(node)           ? 0 :
      BINARY.includes(node.op) ? [ node => new Node(node.op,evaluate(node.left),evaluate(node.right)),
                                    node => new Node(node.op,evaluate(node.left),evaluate(node.right)),
                                    node => new Node(node.op,new Node("-",new Node("*",evaluate(node.left),node.right),new Node("*",node.left,evaluate(node.right))),new Node("^",node.right,2)),
                                    node => new Node("+",new Node("*",evaluate(node.left),node.right),new Node("*",node.left,evaluate(node.right))),
                                    node => new Node("*",evaluate(node.left),new Node("*",node.right,new Node(node.op,node.left,new Node("-",node.right,1)))),
                                  ] [BINARY.indexOf(node.op)] (node) :
      UNARY.includes(node.op)  ? [ node => new Node("*",evaluate(node.left),new Node("cos",node.left)),
                                    node => new Node("*",evaluate(node.left),new Node("*",-1,new Node("sin",node.left))),
                                    node => new Node("*",evaluate(node.left),new Node("+",1,new Node("^",node,2))),
                                    node => new Node("*",evaluate(node.left),node),
                                    node => new Node("*",evaluate(node.left),new Node("/",1,node.left)),
                                  ] [UNARY.indexOf(node.op)] (node) :
      /* variable */             1
    ;
    
    const optimise = node => DEBUG && console.log("<hr>optimise",show(node)) ||
      BINARY.includes(node.op) ? [ left => right => isNumber(left) && isNumber(right) ? left-right : right===0 ? left : new Node(node.op,left,right) ,
                                    left => right => isNumber(left) && isNumber(right) ? left+right : left===0 ? right : right===0 ? left : new Node(node.op,left,right)  ,
                                    left => right => isNumber(left) && isNumber(right) ? left/right : left===0 ? 0 : right===1 ? left : new Node(node.op,left,right) ,
                                    left => right => isNumber(left) && isNumber(right) ? left*right : left===0 || right===0 ? 0 : left===1 ? right : right===1 ? left : new Node(node.op,left,right) ,
                                    left => right => isNumber(left) && isNumber(right) ? Math.pow(left,right) : left===0 ? 0 : left===1 ? 1 : right===0 ? 1 : right===1 ? left : new Node(node.op,left,right) ,
                                  ] [BINARY.indexOf(node.op)] (optimise(node.left)) (optimise(node.right)) :
      UNARY.includes(node.op)  ? new Node(node.op,optimise(node.left)) :
      /* number or variable */ node
    ;
    
    const show = node =>
      isNumber(node)           ? `${node}` :
      BINARY.includes(node.op) ? `(${node.op} ${show(node.left)} ${show(node.right)})` :
      UNARY.includes(node.op)  ? `(${node.op} ${show(node.left)})` :
      /* variable */             `${node.op}`
    ;
    
    function Node(op,left,right) {
      this.op = op;
      this.left = left;
      this.right = right;
    }
    
    const isNumber = t => Number.isFinite(Number(t)) ;
    const BINARY = "-+/*^";
    const UNARY = ["sin","cos","tan","exp","ln"];
    Codiga Logo
    Codiga Hub
    • Rulesets
    • Playground
    • Snippets
    • Cookbooks
    soc-2 icon

    We are SOC-2 Compliance Certified

    G2 high performer medal

    Codiga – All rights reserved 2022.