SHARE
TWEET

Untitled

a guest Apr 21st, 2019 80 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "use strict";
  2.  
  3. const VARIABLES = new Map([
  4.     ["x", 0],
  5.     ["y", 1],
  6.     ["z", 2]
  7. ]);
  8.  
  9. const ZERO = new Const(0);
  10. const ONE = new Const(1);
  11. const TWO = new Const(2);
  12.  
  13. function ExpressionFactory(func, funcName, diffAlg) {
  14.     function Operation(...args) {
  15.         this.operands = args;
  16.     }
  17.  
  18.     Operation.prototype.toString = function () {
  19.         return this.operands.join(" ") + " " + funcName;
  20.     };
  21.     Operation.prototype.evaluate = function (...args) {
  22.         const result = this.operands.map((value) => value.evaluate(...args));
  23.         return func(...result);
  24.     };
  25.     Operation.prototype.diff = function (name) {
  26.         let differentials = this.operands.map((value) => value.diff(name));
  27.         return diffAlg(...this.operands.concat(differentials));
  28.     };
  29.     Operation.prototype.prefix = function () {
  30.         return "(" + funcName + ' ' + this.operands.map(function (value) {
  31.             return value.prefix()
  32.         }).join(" ") + ')';
  33.     };
  34.     Operation.prototype.postfix = function () {
  35.         return "(" + this.operands.map(function (value) {
  36.             return value.postfix()
  37.         }).join(" ") + " " + funcName + ")";
  38.     };
  39.     return Operation;
  40. }
  41.  
  42. function Const(value) {
  43.     this.value = value;
  44. }
  45.  
  46. Const.prototype.toString = function () {
  47.     return this.value.toString();
  48. };
  49. Const.prototype.evaluate = function () {
  50.     return this.value;
  51. };
  52. Const.prototype.diff = () => ZERO;
  53. Const.prototype.prefix = Const.prototype.toString;
  54. Const.prototype.postfix = Const.prototype.prefix;
  55.  
  56. function Variable(name) {
  57.     this.name = name;
  58.     this.index = VARIABLES.get(name);
  59. }
  60.  
  61. Variable.prototype.toString = function () {
  62.     return this.name;
  63. };
  64. Variable.prototype.evaluate = function (...args) {
  65.     return args[this.index];
  66. };
  67. Variable.prototype.diff = function (name) {
  68.     return name === this.name ? ONE : ZERO;
  69. };
  70. Variable.prototype.prefix = function () {
  71.     return this.name;
  72. };
  73. Variable.prototype.postfix = Variable.prototype.prefix;
  74.  
  75. const Add = ExpressionFactory((x, y) => x + y, "+",
  76.     (x, y, dx, dy) => new Add(dx, dy));
  77. const Subtract = ExpressionFactory((x, y) => x - y, "-",
  78.     (x, y, dx, dy) => new Subtract(dx, dy));
  79. const Multiply = ExpressionFactory((x, y) => x * y, "*",
  80.     (x, y, dx, dy) => new Add(new Multiply(dx, y), new Multiply(dy, x)));
  81. const Divide = ExpressionFactory((x, y) => x / y, "/",
  82.     (x, y, dx, dy) => new Divide(new Subtract(new Multiply(dx, y), new Multiply(dy, x)), new Multiply(y, y)));
  83. const Negate = ExpressionFactory((x) => -x, "negate",
  84.     (x, dx) => new Negate(dx));
  85. const Sqrt = ExpressionFactory(x => Math.sqrt(x), "sqrt",
  86.     (x, dx) => new Divide(new Sqrt(dx), new Multiply(TWO, new Sqrt(x))));
  87. const Sum = ExpressionFactory((...args) => args.reduce((sum, current) => sum + current, 0),
  88.     "sum", (...args) => new Sum(...args.slice(args.length / 2)));
  89. const Avg = ExpressionFactory((...args) => args.reduce((sum, current) => sum + current, 0) / args.length,
  90.     "avg", (...args) => new Avg(...args.slice(args.length / 2)));
  91. const Sumexp = ExpressionFactory(
  92.     (...args) => args.reduce((sum, current) => sum + Math.exp(current), 0),
  93.     "sumexp",
  94.     (...args) =>
  95.         new Sum(...(args.slice(0, args.length / 2)).map(
  96.             (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
  97. );
  98. const Softmax = ExpressionFactory(
  99.     (...args) => Math.exp(args[0]) / args.reduce((sum, current) => sum + Math.exp(current), 0),
  100.     "softmax",
  101.     (...args) =>
  102.         new Divide(
  103.             new Subtract(
  104.                 new Multiply(
  105.                     new Multiply(args[args.length / 2], new Sumexp(args[0])),
  106.                     new Sumexp(...(args.slice(0, args.length / 2)))),
  107.                 new Multiply(
  108.                     new Sumexp(args[0]),
  109.                     new Sum(...(args.slice(0, args.length / 2)).map(
  110.                         (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
  111.                 )),
  112.             new Multiply(
  113.                 new Sumexp(...(args.slice(0, args.length / 2))),
  114.                 new Sumexp(...(args.slice(0, args.length / 2))))
  115.         )
  116. );
  117. const Sumsq = ExpressionFactory(
  118.     (...args) => args.reduce((sum, current) => sum + Math.pow(current, 2), 0),
  119.     "sumsq",
  120.     (...args) => new Sum(...(args.slice(0, args.length / 2)).map(
  121.         (v, ind) =>
  122.             new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))));
  123. const Length = ExpressionFactory(
  124.     (...args) => Math.sqrt(args.reduce((sum, current) => sum + Math.pow(current, 2), 0)),
  125.     "length",
  126.     (...args) => args.length === 0 ? ZERO :
  127.         new Divide(
  128.             new Sum(...(args.slice(0, args.length / 2)).map(
  129.                 (v, ind) => new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))),
  130.             new Multiply(
  131.                 TWO,
  132.                 new Sqrt(new Sumsq(...(args.slice(0, args.length / 2))))
  133.             )
  134.         )
  135. );
  136.  
  137. const OPERATIONS = new Map([
  138.     ['+', [Add, 2]],
  139.     ['-', [Subtract, 2]],
  140.     ['*', [Multiply, 2]],
  141.     ['/', [Divide, 2]],
  142.     ['negate', [Negate, 1]],
  143.     ['sqrt', [Sqrt, 1]],
  144.     ['sum', [Sum, 0]],
  145.     ['avg', [Avg, 0]],
  146.     ['sumexp', [Sumexp, 0]],
  147.     ['softmax', [Softmax, 0]],
  148.     ['length', [Length, 0]],
  149.     ['sumsq', [Sumsq, 0]]
  150. ]);
  151.  
  152. const parse = expression => {
  153.     let tokens = expression.trim().split(/\s+/);
  154.     let stack = [];
  155.     for (const token of tokens) {
  156.         if (OPERATIONS.has(token)) {
  157.             let operation = OPERATIONS.get(token)[0];
  158.             let count = OPERATIONS.get(token)[1];
  159.             stack.push(new operation(...stack.splice(stack.length - count, count)));
  160.         } else if (VARIABLES.has(token)) {
  161.             stack.push(new Variable(token));
  162.         } else {
  163.             stack.push(new Const(Number(token)));
  164.         }
  165.     }
  166.     return stack.pop();
  167. };
  168.  
  169. function ParserError(message) {
  170.     this.message = message;
  171. }
  172.  
  173. ParserError.prototype = Error.prototype;
  174.  
  175. let mode;
  176. let expression;
  177. let pos = 0;
  178.  
  179. function isDigit(operand) {
  180.     return operand.length !== 0 && Number.isInteger(+operand);
  181. }
  182.  
  183. function skipSpaces() {
  184.     while (/\s/.test(expression[pos]) && pos < expression.length) {
  185.         pos++
  186.     }
  187. }
  188.  
  189. function movePointer(object) {
  190.     pos += object.toString().length;
  191. }
  192.  
  193. function getObject() {
  194.     let to = pos;
  195.     while (!/\s/.test(expression[to]) && expression[to] !== ')' && expression[to] !== '(' && to < expression.length) {
  196.         to++;
  197.     }
  198.     return expression.slice(pos, to);
  199. }
  200.  
  201. function initialize(object) {
  202.     if (VARIABLES.has(object)) {
  203.         return new Variable(object);
  204.     } else if (isDigit(object)) {
  205.         return new Const((Number(object)));
  206.     } else if (OPERATIONS.has(object)) {
  207.         return object;
  208.     } else {
  209.         throw new ParserError("Unknown object: \"" + object + "\"");
  210.     }
  211. }
  212.  
  213. function parsePart() {
  214.     let objectsStack = [];
  215.  
  216.     function getObjects() {
  217.         skipSpaces();
  218.         while (expression[pos] !== ')' && pos < expression.length) {
  219.             skipSpaces();
  220.             if (expression[pos] === '(') {
  221.                 objectsStack.push(parsePart());
  222.             } else {
  223.                 let object = getObject();
  224.                 movePointer(object);
  225.                 objectsStack.push(initialize(object));
  226.             }
  227.             skipSpaces();
  228.         }
  229.     }
  230.  
  231.     skipSpaces();
  232.     if (expression[pos] === '(') {
  233.         pos++;
  234.         getObjects();
  235.         let operation = eval("objectsStack.".concat(mode));
  236.         if (objectsStack.some(object => OPERATIONS.has(object))) {
  237.             throw new ParserError("Operation among arguments")
  238.         }
  239.         if (expression[pos++] !== ')') {
  240.             throw new ParserError("Missing )");
  241.         }
  242.         let func;
  243.         if (OPERATIONS.has(operation)) {
  244.             func = OPERATIONS.get(operation)[0];
  245.         } else {
  246.             throw new ParserError("Incorrect operation: " + "\"" + operation + "\"");
  247.         }
  248.         let expectedCount = OPERATIONS.get(operation)[1];
  249.         if (expectedCount === objectsStack.length || OPERATIONS.get(operation)[1] === 0) {
  250.             return new func(...objectsStack.splice(0));
  251.         } else {
  252.             throw new ParserError("Incorrect count of arguments. Expected: " + expectedCount + " met: " + objectsStack.length);
  253.         }
  254.     } else {
  255.         getObjects();
  256.         if (objectsStack.length !== 1) {
  257.             throw new ParserError("Missing (");
  258.         }
  259.     }
  260.     return objectsStack.pop();
  261. }
  262.  
  263. function parseSide(s) {
  264.     expression = s.trim();
  265.     if (expression === '') {
  266.         throw new ParserError("Empty input");
  267.     }
  268.     pos = 0;
  269.     let answer = parsePart();
  270.     if (pos < expression.length) {
  271.         throw new ParserError("Excessive info")
  272.     }
  273.     return answer;
  274. }
  275.  
  276. function parsePrefix(s) {
  277.     mode = "shift()";
  278.     return parseSide(s);
  279. }
  280.  
  281. function parsePostfix(s) {
  282.     mode = "pop()";
  283.     return parseSide(s);
  284. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top