Advertisement
Guest User

Untitled

a guest
Mar 26th, 2019
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2.     let expression = (function () {
  3.  
  4.         let exceptions = function () {
  5.             let exceptionFactory = function (msg) {
  6.                 let Exception = function (idx, token) {
  7.                     this.name = msg + " on position " + idx + ", where '" + token + "' is";
  8.                 };
  9.                 Exception.prototype = Error.prototype;
  10.                 return Exception;
  11.             };
  12.             let ClosingParenthesisMissingException = exceptionFactory(
  13.                 'Closing parenthesis expected'
  14.             );
  15.             let ExpressionEndExpectedException = exceptionFactory(
  16.                 'End of expression expected'
  17.             );
  18.             let OperationExpectedException = exceptionFactory(
  19.                 'Operation symbol expected'
  20.             );
  21.             let OperandExpectedException = exceptionFactory(
  22.                 'Operand expected'
  23.             );
  24.             let EndOfConstantExpectedException = exceptionFactory(
  25.                 'End of constant expected'
  26.             );
  27.             let InvalidOperandsAmountException = exceptionFactory(
  28.                 'Invalid operands amount found'
  29.             );
  30.  
  31.             return {
  32.                 ClosingParenthesisMissingException: ClosingParenthesisMissingException,
  33.                 ExpressionEndExpectedException: ExpressionEndExpectedException,
  34.                 OperationExpectedException: OperationExpectedException,
  35.                 OperandExpectedException: OperandExpectedException,
  36.                 EndOfConstantExpectedException: EndOfConstantExpectedException,
  37.                 InvalidOperandsAmountException: InvalidOperandsAmountException,
  38.             }
  39.         }();
  40.  
  41.         function Const(value) {
  42.             this.value = value;
  43.         }
  44.  
  45.         const ZERO = new Const(0);
  46.         const ONE = new Const(1);
  47.  
  48.         Const.prototype.evaluate = function () {
  49.             return this.value;
  50.         };
  51.  
  52.         Const.prototype.toString = function () {
  53.             return this.value.toString();
  54.         };
  55.  
  56.         Const.prototype.prefix = Const.prototype.toString;
  57.  
  58.         Const.prototype.diff = function () {
  59.             return ZERO;
  60.         };
  61.  
  62.         const VARIABLES = {
  63.             "x" : 0,
  64.             "y" : 1,
  65.             "z" : 2
  66.         };
  67.  
  68.         function Variable(name) {
  69.             this.name = name;
  70.         }
  71.  
  72.         Variable.prototype.evaluate = function () {
  73.             return arguments[VARIABLES[this.name]];
  74.         };
  75.  
  76.         Variable.prototype.toString = function () {
  77.             return this.name.toString();
  78.         };
  79.  
  80.  
  81.         Variable.prototype.prefix = Variable.prototype.toString;
  82.  
  83.         Variable.prototype.diff = function (name) {
  84.             if (this.name === name) {
  85.                 return ONE;
  86.             } else {
  87.                 return ZERO;
  88.             }
  89.         };
  90.  
  91.         function Operation() {
  92.             this.operands = Array.from(arguments);
  93.             this.getOperands = function() {
  94.                 return this.operands;
  95.             }
  96.         }
  97.  
  98.         Operation.prototype.prefix = function() {
  99.             let operands = this.getOperands();
  100.             let res = "(" + this.operationStr + ' ';
  101.             for (let i = 0; i < operands.length - 1; i++) {
  102.                 res += operands[i].prefix();
  103.                 res += ' ';
  104.             }
  105.             if (operands.length > 0) {
  106.                 res += operands[operands.length - 1].prefix();
  107.             }
  108.             res += ')';
  109.             return res;
  110.         };
  111.  
  112.         Operation.prototype.evaluate = function (...args) {
  113.             let result = [];
  114.             this.getOperands().map(function (operand) {
  115.                 result.push(operand.evaluate(...args));
  116.             });
  117.             return this.doOperation(...result);
  118.         };
  119.  
  120.         Operation.prototype.diff = function (name) {
  121.             let args = [];
  122.             this.getOperands().map(function (operand) {
  123.                 args.push(operand);
  124.                 args.push(operand.diff(name));
  125.             });
  126.             return this.doDiff(...args);
  127.         };
  128.  
  129.         Operation.prototype.toString = function () {
  130.             let res = "";
  131.             this.getOperands().map(function (operand) {
  132.                 res += operand.toString() + ' ';
  133.             });
  134.             res += this.operationStr;
  135.             return res;
  136.         };
  137.  
  138.         function operationFactory(operationStr, doOperation, doDiff, doSimplify) {
  139.             function Constructor() {
  140.                 Operation.apply(this, arguments);
  141.                 return this;
  142.             }
  143.             Constructor.prototype = Object.create(Operation.prototype);
  144.             Constructor.prototype.operationStr = operationStr;
  145.             Constructor.prototype.constructor = Constructor;
  146.             Constructor.prototype.doOperation = doOperation;
  147.             Constructor.prototype.doDiff = doDiff;
  148.             return Constructor;
  149.         }
  150.  
  151.         function checkZero(operand) {
  152.             if (operand instanceof Const) {
  153.                 return operand.value === 0;
  154.             }
  155.             return false;
  156.         }
  157.  
  158.         function checkOne(operand) {
  159.             if (operand instanceof Const) {
  160.                 return operand.value === 1;
  161.             }
  162.             return false;
  163.         }
  164.  
  165.         const Add = operationFactory('+',
  166.             (x, y) => x + y,
  167.             (x, dx, y, dy) => new Add(dx, dy));
  168.  
  169.         const Subtract = operationFactory('-',
  170.             (x, y) => x - y,
  171.             (x, dx, y, dy) => new Subtract(dx, dy));
  172.  
  173.         const Multiply = operationFactory('*',
  174.             (x, y) => x * y,
  175.             (x, dx, y, dy) => new Add(new Multiply(dx, y), new Multiply(dy, x)));
  176.  
  177.         const Divide = operationFactory('/',
  178.             (x, y) => x / y,
  179.             (x, dx, y, dy) => new Divide(new Subtract(new Multiply(dx, y), new Multiply(dy, x)), new Multiply(y, y)));
  180.  
  181.         const ArcTan = operationFactory('atan',
  182.             (x) => Math.atan(x),
  183.             (x, dx) => new Divide(dx, new Add(ONE, new Multiply(x, x))));
  184.  
  185.         const ArcTan2 = operationFactory('atan2',
  186.             (x, y) => Math.atan2(x, y),
  187.             (x, dx, y, dy) => new Divide(new Subtract(new Multiply(dx, y), new Multiply(dy, x)), new Add(new Multiply(y, y), new Multiply(x, x))));
  188.  
  189.         const Negate = operationFactory('negate', (x) => -x, (x, dx) => new Negate(dx));
  190.  
  191.         const Sum = operationFactory('sum',
  192.             (...operands) => {
  193.                 let result = 0;
  194.                 for (let operand of operands) {
  195.                     result += operand;
  196.                 }
  197.                 return result;
  198.             },
  199.             (...operands) => {
  200.                 let arguments = [];
  201.                 for (let i = 1; i < operands.length; i += 2) {
  202.                     arguments.push(operands[i]);
  203.                 }
  204.                 return new Sum(...arguments);
  205.             });
  206.  
  207.         const Sumexp = operationFactory('sumexp',
  208.             function(...operands) {
  209.                 let result = 0;
  210.                 for (let operand of operands) {
  211.                     result += Math.pow(Math.E, operand);
  212.                 }
  213.                 return result;
  214.             },
  215.             function (...operands) {
  216.                 let arguments = [];
  217.                 for (let i = 1; i < operands.length; i += 2) {
  218.                     arguments.push(new Multiply(operands[i], new Sumexp(operands[i - 1])));
  219.                 }
  220.                 return new Sum(...arguments);
  221.             });
  222.  
  223.         const Softmax = operationFactory('softmax',
  224.             function (...operands) {
  225.                 let result = 0;
  226.                 for (let operand of operands) {
  227.                     result += Math.pow(Math.E, operand);
  228.                 }
  229.                 result = Math.pow(Math.E, operands[0]) / result;
  230.                 return result;
  231.             },
  232.             function (...operands) {
  233.                 let operandsx = [];
  234.                 for (let i = 0; i < operands.length; i += 2) {
  235.                     operandsx.push(operands[i]);
  236.                 }
  237.  
  238.                 let operandsdx = [];
  239.                 for (let i = 1; i < operands.length; i += 2) {
  240.                     operandsdx.push(operands[i]);
  241.                 }
  242.  
  243.                 let denominator = new Sumexp(...operandsx);
  244.                 let numerator = new Sumexp(operandsx[0]);
  245.  
  246.                 let res = new Divide(numerator, denominator);
  247.                 return res.doDiff(numerator, numerator.doDiff(operandsx[0], operandsdx[0]), denominator, denominator.doDiff(...operands));
  248.             });
  249.  
  250.         const CONSTANT = {
  251.             "one" : 1,
  252.             "two" : 2
  253.         };
  254.  
  255.         const OPERATION = {
  256.             "+" : Add,
  257.             "-" : Subtract,
  258.             "*" : Multiply,
  259.             "/" : Divide,
  260.             "negate": Negate,
  261.             "atan": ArcTan,
  262.             "atan2": ArcTan2,
  263.             "sum": Sum,
  264.             "sumexp": Sumexp,
  265.             "softmax": Softmax
  266.         };
  267.  
  268.         const CNT_ARGUMENTS = {
  269.             "+" : 2,
  270.             "-" : 2,
  271.             "*" : 2,
  272.             "/" : 2,
  273.             "negate": 1,
  274.             "atan": 1,
  275.             "atan2": 2,
  276.             "sum": null,
  277.             "sumexp": null,
  278.             "softmax": null
  279.         };
  280.  
  281.         function parse(expr) {
  282.             const tokens = expr.split(" ").filter(f => f.length > 0);
  283.             let stack = [];
  284.             tokens.map(function (token) {
  285.                 if (token in VARIABLES) {
  286.                     stack.push(new Variable(token));
  287.                 } else if (token in OPERATION) {
  288.                     let arguments = stack.slice(stack.length - CNT_ARGUMENTS[token], stack.length);
  289.                     stack.splice(stack.length - CNT_ARGUMENTS[token], CNT_ARGUMENTS[token]);
  290.                     stack.push(new OPERATION[token](...arguments));
  291.                 } else if (token in CONSTANT) {
  292.                     stack.push(new Const(CONSTANT[token]));
  293.                 } else {
  294.                     stack.push(new Const(Number(token)));
  295.                 }
  296.             });
  297.  
  298.             return stack.pop();
  299.         }
  300.  
  301.         let Tokenizer = function (expression) {
  302.             this.pos = 0;
  303.             this.prevToken = "";
  304.             this.token = "";
  305.  
  306.             let isWhitespace = function (symbol) {
  307.                 return /[\s]/.test(symbol);
  308.             };
  309.  
  310.             this.nextToken = function () {
  311.                 this.prevToken = this.token;
  312.                 while (this.pos < expression.length && isWhitespace(expression[this.pos])) {
  313.                     this.pos++;
  314.                 }
  315.                 this.token = "";
  316.                 if (expression[this.pos] === '(' || expression[this.pos] === ')') {
  317.                     this.token = expression[this.pos++];
  318.                 } else {
  319.                     while (this.pos < expression.length &&
  320.                     !isWhitespace(expression[this.pos]) && expression[this.pos] !== '(' && expression[this.pos] !== ')') {
  321.                         this.token += expression[this.pos++];
  322.                     }
  323.                 }
  324.             };
  325.         };
  326.  
  327.         let parseOperand = function (tokenizer, parseExpression) {
  328.             if (tokenizer.token === '(') {
  329.                 return parseExpression();
  330.             } else if (tokenizer.token in VARIABLES) {
  331.                 tokenizer.nextToken();
  332.                 return new Variable(tokenizer.prevToken);
  333.             } else if (tokenizer.token !== '' && !isNaN(tokenizer.token)) {
  334.                 tokenizer.nextToken();
  335.                 return new Const(parseInt(tokenizer.prevToken));
  336.             } else {
  337.                 throw new exceptions.OperandExpectedException(tokenizer.pos, tokenizer.token);
  338.             }
  339.         };
  340.  
  341.         let parsePrefix = function (expression) {
  342.             let tokenizer = new Tokenizer(expression);
  343.  
  344.             let parseExpression = function () {
  345.                 if (tokenizer.token === '(') {
  346.                     tokenizer.nextToken();
  347.                     if (!(tokenizer.token in OPERATION)) {
  348.                         throw new exceptions.OperationExpectedException(tokenizer.pos, tokenizer.token);
  349.                     }
  350.                     let op = OPERATION[tokenizer.token];
  351.                     let cnt = CNT_ARGUMENTS[tokenizer.token];
  352.                     tokenizer.nextToken();
  353.                     let arguments = [];
  354.                     let i = 0;
  355.                     while (i !== cnt) {
  356.                         i++;
  357.                         if (cnt === null && tokenizer.token === ')') {
  358.                             break;
  359.                         }
  360.                         arguments.push(parseOperand(tokenizer, parseExpression));
  361.                     }
  362.  
  363.                     if (tokenizer.token !== ')') {
  364.                         throw new exceptions.ClosingParenthesisMissingException(tokenizer.pos, tokenizer.token);
  365.                     }
  366.                     tokenizer.nextToken();
  367.                     return new op(...arguments);
  368.                 } else {
  369.                     return parseOperand(tokenizer, parseExpression);
  370.                 }
  371.             };
  372.  
  373.             tokenizer.nextToken();
  374.             let res = parseExpression();
  375.             if (tokenizer.token !== "") {
  376.                 throw new exceptions.ExpressionEndExpectedException(tokenizer.pos, tokenizer.token);
  377.             }
  378.             return res;
  379.         };
  380.  
  381.         return {
  382.             "Const": Const,
  383.             "Variable": Variable,
  384.  
  385.             "ArcTan": ArcTan,
  386.             "ArcTan2": ArcTan2,
  387.             "Negate": Negate,
  388.             "Sum": Sum,
  389.             "Sumexp": Sumexp,
  390.             "Softmax": Softmax,
  391.  
  392.  
  393.             "Add": Add,
  394.             "Subtract": Subtract,
  395.             "Multiply": Multiply,
  396.             "Divide": Divide,
  397.             "parse": parse,
  398.             "parsePrefix": parsePrefix
  399.         }
  400.     })();
  401.  
  402.  
  403.     let
  404.         Const = expression.Const,
  405.         Variable = expression.Variable,
  406.  
  407.         ArcTan = expression.ArcTan,
  408.         Negate = expression.Negate,
  409.  
  410.         Add = expression.Add,
  411.         Subtract = expression.Subtract,
  412.         Multiply = expression.Multiply,
  413.         Divide = expression.Divide,
  414.         Sum = expression.Sum,
  415.         Sumexp = expression.Sumexp,
  416.         Softmax = expression.Softmax,
  417.  
  418.         parse = expression.parse,
  419.         parsePrefix = expression.parsePrefix;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement