Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- let ind = 0;
- let expr = "";
- function MyException(message) {
- this.message = message + "on position: " + ind;
- }
- function getSumInArray(arr) {
- return arr.length === 0 ? 0 : arr.reduce((a, b) => a + b);
- }
- function checkEndOfInput() {
- skipWhiteSpaces();
- if (ind < expr.length) {
- throw new MyException("Cannot parse next. Stopped on position: " + ind);
- }
- }
- function getFullByRegExp(reg) {
- let res = "";
- while (ind < expr.length && reg.test(expr[ind])) {
- res += expr[ind];
- ind++;
- }
- return res;
- }
- function skipWhiteSpaces() {
- while (ind < expr.length && /\s/.test(expr[ind])) {
- ind++;
- }
- }
- function isNumber(s) {
- return s.length !== 0 && Number.isInteger(+s);
- }
- function chooseVariableOrNumberOrThrowException(token) {
- if (VARIABLES.has(token)) {
- return new Variable(token);
- } else if (isNumber(token)) {
- return new Const(parseInt(token, 10));
- } else {
- throw new MyException("Unknown variable: " + token);
- }
- }
- function readBrackets(mode) {
- ind++; // вызывается всегда при '('
- let operation;
- let ops;
- if (mode === 0) {
- operation = getNextToken();
- ops = getOperands(mode);
- } else if (mode === 1) {
- ops = getOperands(mode);
- operation = ops.pop();
- }
- if (!OPERATIONS.has(operation)) {
- throw new MyException("Unknown operation: '" + operation + "'");
- }
- if (OPERATIONS.get(operation)[1] !== -1 && OPERATIONS.get(operation)[1] !== ops.length) {
- throw new MyException("For operation: '" + operation + "' expected " +
- OPERATIONS.get(operation)[1] + " arguments. Found: " + ops);
- }
- return new (OPERATIONS.get(operation)[0])(...ops);
- }
- function getNextToken() {
- skipWhiteSpaces();
- return getFullByRegExp(/[^\s()]/);
- }
- function getOperands(mode) {
- let arr = []; // аргументы - тоже функции (инвариант)
- while (true) {
- let token = getNextToken();
- skipWhiteSpaces();
- if (mode === 1 && expr[ind] === ')') {
- arr.push(token); // operation
- ind++;
- return arr;
- }
- if (token.length === 0) {
- if (expr[ind] === '(') {
- arr.push(readBrackets(mode));
- } else if (expr[ind] === ')') {
- ind++;
- return arr;
- } else {
- throw new MyException("Problems with brackets");
- }
- } else {
- arr.push(chooseVariableOrNumberOrThrowException(token));
- }
- }
- }
- function parseAnyFix(mode, str) {
- // mode = 0 - prefix
- // mode = 1 - postfix
- expr = str;
- ind = 0;
- skipWhiteSpaces();
- if (expr[ind] === '(') {
- let res = readBrackets(mode);
- checkEndOfInput();
- return res;
- }
- let token = getFullByRegExp(/\S/);
- checkEndOfInput();
- if (token.length === 0) {
- throw new MyException("Empty input");
- } else {
- return chooseVariableOrNumberOrThrowException(token);
- }
- }
- function parsePrefix(str) {
- return parseAnyFix(0, str);
- }
- function parsePostfix(str) {
- return parseAnyFix(1, str);
- }
- function newOperation(action, symbol, howToDiff) {
- function Operation(...args) {
- this.operands = args;
- }
- Operation.prototype.toString = function () {
- return this.operands.join(" ") + " " + symbol;
- };
- Operation.prototype.prefix = function () {
- return "(" + symbol + " " + this.operands.map(value => value.prefix()).join(" ") + ")";
- };
- Operation.prototype.postfix = function () {
- return "(" + this.operands.map(value => value.postfix()).join(" ") + " " + symbol + ")";
- };
- Operation.prototype.evaluate = function (...args) {
- return action(...this.operands.map(operand => operand.evaluate(...args)));
- };
- Operation.prototype.diff = function (v) {
- const ops = this.operands;
- return howToDiff.apply(this, ops.concat(ops.map(value => value.diff(v))));
- };
- return Operation;
- }
- function Const(x) {
- this.value = x;
- }
- Const.prototype.toString = function () {
- return this.value.toString();
- };
- Const.prototype.evaluate = function () {
- return this.value;
- };
- Const.prototype.prefix = Const.prototype.toString;
- Const.prototype.postfix = Const.prototype.toString;
- Const.prototype.diff = () => ZERO;
- function Variable(s) {
- this.name = s;
- this.index = VARIABLES.get(s);
- }
- Variable.prototype.toString = function () {
- return this.name;
- };
- Variable.prototype.evaluate = function (...args) {
- return args[this.index];
- };
- Variable.prototype.prefix = Variable.prototype.toString;
- Variable.prototype.postfix = Variable.prototype.toString;
- Variable.prototype.diff = function (v) {
- return v === this.name ? ONE : ZERO;
- };
- const Add = newOperation(
- (a, b) => a + b,
- "+",
- (a, b, da, db) => new Add(da, db));
- const Subtract = newOperation(
- (a, b) => a - b,
- "-",
- (a, b, da, db) => new Subtract(da, db));
- const Multiply = newOperation(
- (a, b) => a * b,
- "*",
- (a, b, da, db) => new Add(new Multiply(da, b), new Multiply(a, db)));
- const Divide = newOperation(
- (a, b) => a / b,
- "/",
- (a, b, da, db) => new Divide(new Subtract(new Multiply(da, b), new Multiply(a, db)), new Multiply(b, b)));
- const Negate = newOperation(
- a => -a,
- "negate",
- (a, da) => new Negate(da));
- const Sqrt = newOperation(a => Math.sqrt(a));
- const Sum = newOperation(
- (...args) => getSumInArray(args),
- "sum",
- (...args) => new Sum(...args.slice(args.length / 2)));
- const Avg = newOperation(
- (...args) => getSumInArray(args) / args.length,
- "avg",
- (...args) => new Avg(...args.slice(args.length / 2)));
- const Sumsq = newOperation(
- (...args) => getSumInArray(args.map(v => v * v)),
- "sumsq",
- (...args) => new Sum(...(args.slice(0, args.length / 2)).map(
- (v, ind) =>
- new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))));
- const Length = newOperation(
- (...args) => Math.sqrt(getSumInArray(args.map(v => v * v))),
- "length",
- (...args) => args.length === 0 ? ZERO :
- new Divide(
- new Sum(...(args.slice(0, args.length / 2)).map(
- (v, ind) => new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))),
- new Multiply(
- TWO,
- new Sqrt(new Sumsq(...(args.slice(0, args.length / 2))))
- )
- )
- );
- const Sumexp = newOperation(
- (...args) => getSumInArray(args.map(v => Math.exp(v))),
- "sumexp",
- (...args) =>
- new Sum(...(args.slice(0, args.length / 2)).map(
- (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
- );
- const Softmax = newOperation(
- (...args) => Math.exp(args[0]) / getSumInArray(args.map(v => Math.exp(v))),
- "softmax",
- (...args) =>
- new Divide(
- new Subtract(
- new Multiply(
- new Multiply(args[args.length / 2], new Sumexp(args[0])),
- new Sumexp(...(args.slice(0, args.length / 2)))),
- new Multiply(
- new Sumexp(args[0]),
- new Sum(...(args.slice(0, args.length / 2)).map(
- (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
- )),
- new Multiply(
- new Sumexp(...(args.slice(0, args.length / 2))),
- new Sumexp(...(args.slice(0, args.length / 2))))
- )
- );
- const OPERATIONS = new Map([
- ['+', [Add, 2]],
- ['-', [Subtract, 2]],
- ['*', [Multiply, 2]],
- ['/', [Divide, 2]],
- ['negate', [Negate, 1]],
- ['sum', [Sum, -1]],
- ['avg', [Avg, -1]],
- ['sumexp', [Sumexp, -1]],
- ['softmax', [Softmax, -1]],
- ['sumsq', [Sumsq, -1]],
- ['length', [Length, -1]]
- ]);
- const ZERO = new Const(0);
- const ONE = new Const(1);
- const TWO = new Const(2);
- const VARIABLES = new Map([
- ["x", 0],
- ["y", 1],
- ["z", 2]
- ]);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement