Advertisement
IzhanVarsky

Untitled

Apr 14th, 2019
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "use strict";
  2.  
  3. let ind = 0;
  4. let expr = "";
  5.  
  6. function getSumInArray(arr) {
  7.     let sum = 0;
  8.     for (let k of arr) {
  9.         sum += k;
  10.     }
  11.     return sum;
  12. }
  13.  
  14. function MyException(message) {
  15.     this.message = message
  16. }
  17.  
  18. function getFullByRegExp(reg) {
  19.     // /\d/ - digits
  20.     // /\s/ - blank space
  21.     let res = "";
  22.     while (ind < expr.length && reg.test(expr[ind])) {
  23.         res += expr[ind];
  24.         ind++;
  25.     }
  26.     return res;
  27. }
  28.  
  29. function skipWhiteSpaces() {
  30.     while (ind < expr.length && /\s/.test(expr[ind])) {
  31.         ind++;
  32.     }
  33. }
  34.  
  35. function isNumber(s) {
  36.     if (s.length === 0) return false;
  37.     let pos = 0;
  38.     if (s[0] === '-' || s[0] === '+') {
  39.         if (s.length > 1) {
  40.             pos++;
  41.         } else {
  42.             return false;
  43.         }
  44.     }
  45.     while (pos < s.length) {
  46.         if (/\d/.test(s[pos])) {
  47.             pos++;
  48.         } else {
  49.             return false;
  50.         }
  51.     }
  52.     return true;
  53. }
  54.  
  55. function readBrackets(mode) {
  56.     ind++; // вызывается всегда при '('
  57.     let operation;
  58.     let ops;
  59.     if (mode === 0) {
  60.         operation = getNextToken();
  61.         ops = getOperands(mode);
  62.     } else if (mode === 1) {
  63.         let tokens = getOperands(mode);
  64.         operation = tokens[tokens.length - 1];
  65.         ops = tokens.slice(0, tokens.length - 1);
  66.     }
  67.     if (!OPERATIONS.has(operation)) {
  68.         throw new MyException("Unknown operation: " + operation);
  69.     }
  70.     if (OPERATIONS.get(operation)[1] !== 0 && OPERATIONS.get(operation)[1] !== ops.length) {
  71.         throw new MyException("For operation: " + operation + " expected " +
  72.             OPERATIONS.get(operation)[1] + " arguments. Found: " + ops);
  73.     }
  74.     return new (OPERATIONS.get(operation)[0])(...ops);
  75. }
  76.  
  77. function getNextToken() {
  78.     skipWhiteSpaces();
  79.     return getFullByRegExp(/[^\s()]/);
  80. }
  81.  
  82. function getOperands(mode) {
  83.     let curStack = []; // аргументы - тоже функции (инвариант)
  84.     while (true) {
  85.         skipWhiteSpaces();
  86.         let token = getNextToken();
  87.         if (isNumber(token)) {
  88.             curStack.push(new Const(parseInt(token, 10)));
  89.         } else if (token.length !== 0) {
  90.             if (!VARIABLES.has(token)) {
  91.                 skipWhiteSpaces();
  92.                 if (mode === 1 && expr[ind] === ')') {
  93.                     curStack.push(token); // may be an operation
  94.                     continue;
  95.                 }
  96.                 throw new MyException("Unknown variable:" + token);
  97.             }
  98.             curStack.push(new Variable(token));
  99.         } else if (expr[ind] === '(') {
  100.             curStack.push(readBrackets(mode));
  101.         } else if (expr[ind] === ')') {
  102.             ind++;
  103.             return curStack;
  104.         } else {
  105.             // console.log("Never see it again1: " + expr);
  106.             throw new MyException("Unexpected exception." + "Token: " + token + "Pos: " + ind + " Char: " + expr[ind]);
  107.         }
  108.     }
  109. }
  110.  
  111. function parseAnyFix(mode, str) {
  112.     // mode = 0 - prefix
  113.     // mode = 1 - postfix
  114.     expr = str;
  115.     ind = 0;
  116.     skipWhiteSpaces();
  117.     if (expr[ind] === '(') {
  118.         let res = readBrackets(mode);
  119.         skipWhiteSpaces();
  120.         if (ind < expr.length) {
  121.             throw new MyException("Cannot parse next. Stopped on position: " + ind);
  122.         }
  123.         return res;
  124.     }
  125.     let token = getFullByRegExp(/\S/);
  126.     skipWhiteSpaces();
  127.     if (ind < expr.length) {
  128.         throw new MyException("Cannot parse next. Stopped on position: " + ind);
  129.     }
  130.     if (isNumber(token)) {
  131.         return new Const(parseInt(token, 10));
  132.     } else if (token.length !== 0) {
  133.         if (!VARIABLES.has(token)) {
  134.             throw new MyException("Unknown variable:" + token);
  135.         }
  136.         return new Variable(token);
  137.     }
  138.     // console.log("Never see it again2: " + expr);
  139.     throw new MyException("Cannot start parse. Stopped on position: " + ind);
  140. }
  141.  
  142. function parsePrefix(str) {
  143.     return parseAnyFix(0, str);
  144. }
  145.  
  146. function parsePostfix(str) {
  147.     return parseAnyFix(1, str);
  148. }
  149.  
  150. function newOperation(action, symbol, howToDiff) {
  151.     function Operation(...args) {
  152.         this.operands = args;
  153.     }
  154.  
  155.     Operation.prototype.toString = function () {
  156.         return this.operands.join(" ") + " " + symbol;
  157.     };
  158.     Operation.prototype.prefix = function () {
  159.         return "(" + symbol + " " + this.operands.map(value => value.prefix()).join(" ") + ")";
  160.     };
  161.     Operation.prototype.postfix = function () {
  162.         return "(" + this.operands.map(value => value.postfix()).join(" ") + " " + symbol + ")";
  163.     };
  164.     Operation.prototype.evaluate = function (...args) {
  165.         return action(...this.operands.map(operand => operand.evaluate(...args)));
  166.     };
  167.     Operation.prototype.diff = function (v) {
  168.         const ops = this.operands;
  169.         return howToDiff.apply(this, ops.concat(ops.map(value => value.diff(v))));
  170.     };
  171.  
  172.     return Operation;
  173. }
  174.  
  175. function Const(x) {
  176.     this.value = x;
  177. }
  178.  
  179. Const.prototype.toString = function () {
  180.     return this.value.toString();
  181. };
  182. Const.prototype.evaluate = function () {
  183.     return this.value;
  184. };
  185. Const.prototype.prefix = Const.prototype.toString;
  186. Const.prototype.postfix = Const.prototype.toString;
  187. Const.prototype.diff = () => ZERO;
  188.  
  189. function Variable(s) {
  190.     this.name = s;
  191.     this.index = VARIABLES.get(s);
  192. }
  193.  
  194. Variable.prototype.toString = function () {
  195.     return this.name;
  196. };
  197. Variable.prototype.evaluate = function (...args) {
  198.     return args[this.index];
  199. };
  200. Variable.prototype.prefix = Variable.prototype.toString;
  201. Variable.prototype.postfix = Variable.prototype.toString;
  202. Variable.prototype.diff = function (v) {
  203.     return v === this.name ? ONE : ZERO;
  204. };
  205.  
  206. const Add = newOperation(
  207.     (a, b) => a + b,
  208.     "+",
  209.     (a, b, da, db) => new Add(da, db));
  210. const Subtract = newOperation(
  211.     (a, b) => a - b,
  212.     "-",
  213.     (a, b, da, db) => new Subtract(da, db));
  214. const Multiply = newOperation(
  215.     (a, b) => a * b,
  216.     "*",
  217.     (a, b, da, db) => new Add(new Multiply(da, b), new Multiply(a, db)));
  218. const Divide = newOperation(
  219.     (a, b) => a / b,
  220.     "/",
  221.     (a, b, da, db) => new Divide(new Subtract(new Multiply(da, b), new Multiply(a, db)), new Multiply(b, b)));
  222. const Negate = newOperation(
  223.     a => -a,
  224.     "negate",
  225.     (a, da) => new Negate(da));
  226. const Sqrt = newOperation(a => Math.sqrt(a));
  227. const Sum = newOperation(
  228.     (...args) => getSumInArray(args),
  229.     "sum",
  230.     (...args) => new Sum(...args.slice(args.length / 2)));
  231. const Avg = newOperation(
  232.     (...args) => getSumInArray(args) / args.length,
  233.     "avg",
  234.     (...args) => new Avg(...args.slice(args.length / 2)));
  235. const Sumsq = newOperation(
  236.     (...args) => getSumInArray(args.map(v => v * v)),
  237.     "sumsq",
  238.     (...args) => new Sum(...(args.slice(0, args.length / 2)).map(
  239.         (v, ind) =>
  240.             new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))));
  241. const Length = newOperation(
  242.     (...args) => Math.sqrt(getSumInArray(args.map(v => v * v))),
  243.     "length",
  244.     (...args) => args.length === 0 ? ZERO :
  245.         new Divide(
  246.             new Sum(...(args.slice(0, args.length / 2)).map(
  247.                 (v, ind) => new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))),
  248.             new Multiply(
  249.                 TWO,
  250.                 new Sqrt(new Sumsq(...(args.slice(0, args.length / 2))))
  251.             )
  252.         )
  253. );
  254. const Sumexp = newOperation(
  255.     (...args) => getSumInArray(args.map(v => Math.exp(v))),
  256.     "sumexp",
  257.     (...args) =>
  258.         new Sum(...(args.slice(0, args.length / 2)).map(
  259.             (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
  260. );
  261. const Softmax = newOperation(
  262.     (...args) => Math.exp(args[0]) / getSumInArray(args.map(v => Math.exp(v))),
  263.     "softmax",
  264.     (...args) =>
  265.         new Divide(
  266.             new Subtract(
  267.                 new Multiply(
  268.                     new Multiply(args[args.length / 2], new Sumexp(args[0])),
  269.                     new Sumexp(...(args.slice(0, args.length / 2)))),
  270.                 new Multiply(
  271.                     new Sumexp(args[0]),
  272.                     new Sum(...(args.slice(0, args.length / 2)).map(
  273.                         (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
  274.                 )),
  275.             new Multiply(
  276.                 new Sumexp(...(args.slice(0, args.length / 2))),
  277.                 new Sumexp(...(args.slice(0, args.length / 2))))
  278.         )
  279. );
  280.  
  281. const OPERATIONS = new Map([
  282.     ['+', [Add, 2]],
  283.     ['-', [Subtract, 2]],
  284.     ['*', [Multiply, 2]],
  285.     ['/', [Divide, 2]],
  286.     ['negate', [Negate, 1]],
  287.     ['sum', [Sum, 0]],
  288.     ['avg', [Avg, 0]],
  289.     ['sumexp', [Sumexp, 0]],
  290.     ['softmax', [Softmax, 0]],
  291.     ['sumsq', [Sumsq, 0]],
  292.     ['length', [Length, 0]],
  293. ]);
  294.  
  295. const ZERO = new Const(0);
  296. const ONE = new Const(1);
  297. const TWO = new Const(2);
  298.  
  299. const CONSTANTS = new Map([
  300.     ['one', 1],
  301.     ['two', 2],
  302.     ['pi', Math.PI],
  303.     ['e', Math.E]
  304. ]);
  305.  
  306. const VARIABLES = new Map([
  307.     ["x", 0],
  308.     ["y", 1],
  309.     ["z", 2]
  310. ]);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement