Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- let ind = 0;
- let expr = "";
- function getSumInArray(arr) {
- let sum = 0;
- for (let k of arr) {
- sum += k;
- }
- return sum;
- }
- function MyException(message) {
- this.message = message
- }
- function getFullByRegExp(reg) {
- // /\d/ - digits
- // /\s/ - blank space
- 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) {
- if (s.length === 0) return false;
- let pos = 0;
- if (s[0] === '-' || s[0] === '+') {
- if (s.length > 1) {
- pos++;
- } else {
- return false;
- }
- }
- while (pos < s.length) {
- if (/\d/.test(s[pos])) {
- pos++;
- } else {
- return false;
- }
- }
- return true;
- }
- function readBrackets(mode) {
- ind++; // вызывается всегда при '('
- let operation;
- let ops;
- if (mode === 0) {
- operation = getNextToken();
- ops = getOperands(mode);
- } else if (mode === 1) {
- let tokens = getOperands(mode);
- operation = tokens[tokens.length - 1];
- ops = tokens.slice(0, tokens.length - 1);
- }
- if (!OPERATIONS.has(operation)) {
- throw new MyException("Unknown operation: " + operation);
- }
- if (OPERATIONS.get(operation)[1] !== 0 && 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 curStack = []; // аргументы - тоже функции (инвариант)
- while (true) {
- skipWhiteSpaces();
- let token = getNextToken();
- if (isNumber(token)) {
- curStack.push(new Const(parseInt(token, 10)));
- } else if (token.length !== 0) {
- if (!VARIABLES.has(token)) {
- skipWhiteSpaces();
- if (mode === 1 && expr[ind] === ')') {
- curStack.push(token); // may be an operation
- continue;
- }
- throw new MyException("Unknown variable:" + token);
- }
- curStack.push(new Variable(token));
- } else if (expr[ind] === '(') {
- curStack.push(readBrackets(mode));
- } else if (expr[ind] === ')') {
- ind++;
- return curStack;
- } else {
- // console.log("Never see it again1: " + expr);
- throw new MyException("Unexpected exception." + "Token: " + token + "Pos: " + ind + " Char: " + expr[ind]);
- }
- }
- }
- function parseAnyFix(mode, str) {
- // mode = 0 - prefix
- // mode = 1 - postfix
- expr = str;
- ind = 0;
- skipWhiteSpaces();
- if (expr[ind] === '(') {
- let res = readBrackets(mode);
- skipWhiteSpaces();
- if (ind < expr.length) {
- throw new MyException("Cannot parse next. Stopped on position: " + ind);
- }
- return res;
- }
- let token = getFullByRegExp(/\S/);
- skipWhiteSpaces();
- if (ind < expr.length) {
- throw new MyException("Cannot parse next. Stopped on position: " + ind);
- }
- if (isNumber(token)) {
- return new Const(parseInt(token, 10));
- } else if (token.length !== 0) {
- if (!VARIABLES.has(token)) {
- throw new MyException("Unknown variable:" + token);
- }
- return new Variable(token);
- }
- // console.log("Never see it again2: " + expr);
- throw new MyException("Cannot start parse. Stopped on position: " + ind);
- }
- 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, 0]],
- ['avg', [Avg, 0]],
- ['sumexp', [Sumexp, 0]],
- ['softmax', [Softmax, 0]],
- ['sumsq', [Sumsq, 0]],
- ['length', [Length, 0]],
- ]);
- const ZERO = new Const(0);
- const ONE = new Const(1);
- const TWO = new Const(2);
- const CONSTANTS = new Map([
- ['one', 1],
- ['two', 2],
- ['pi', Math.PI],
- ['e', Math.E]
- ]);
- const VARIABLES = new Map([
- ["x", 0],
- ["y", 1],
- ["z", 2]
- ]);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement