Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- let ind = 0;
- let expr = "";
- let mode = 0;
- // mode = 0 - prefix
- // mode = 1 - postfix
- function ParseError(message) {
- this.message = message + ". Expression: " + expr;
- }
- ParseError.prototype = Error.prototype;
- function checkEndOfInput() {
- skipWhiteSpaces();
- if (ind < expr.length) {
- throw new ParseError("Excessive info");
- }
- }
- 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.isFinite(+s);
- }
- function setVariableOrNumberOrThrowException(token) {
- if (VARIABLES.has(token)) {
- return new Variable(token);
- } else if (isNumber(token)) {
- return new Const(Number(token));
- } else {
- throw new ParseError("Unknown object: '" + token + "'");
- }
- }
- function readBrackets() {
- 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 ParseError("Unknown operation: '" + operation + "'");
- }
- if (OPERATIONS.get(operation)[1] !== -1 && OPERATIONS.get(operation)[1] !== ops.length) {
- throw new ParseError("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() {
- 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());
- } else if (expr[ind] === ')') {
- ind++;
- return arr;
- } else {
- throw new ParseError("Problems with brackets");
- }
- } else {
- arr.push(setVariableOrNumberOrThrowException(token));
- }
- }
- }
- function parseAnyFix(code, str) {
- ind = 0;
- expr = str;
- mode = code;
- // console.log(expr);
- skipWhiteSpaces();
- if (expr[ind] === '(') {
- let res = readBrackets();
- checkEndOfInput();
- return res;
- }
- let token = getFullByRegExp(/\S/);
- checkEndOfInput();
- if (token.length === 0) {
- throw new ParseError("Empty input");
- }
- return setVariableOrNumberOrThrowException(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 (variable) {
- return howToDiff(...this.operands.concat(this.operands.map(value => value.diff(variable))));
- };
- 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(Math.sqrt);
- const Sum = newOperation(
- (...args) => args.reduce((a, b) => a + b, 0),
- "sum",
- (...args) => new Sum(...args.slice(args.length / 2)));
- const Avg = newOperation(
- (...args) => args.reduce((a, b) => a + b, 0) / args.length,
- "avg",
- (...args) => new Avg(...args.slice(args.length / 2)));
- const Sumsq = newOperation(
- (...args) => args.reduce((a, b) => a + b * b, 0),
- "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(args.reduce((a, b) => a + b * b, 0)),
- "length",
- (...args) => {
- if (args.length === 0) return ZERO;
- let firstHalf = args.slice(0, args.length / 2);
- return new Divide(
- new Sum(...firstHalf.map(
- (v, ind) => new Multiply(new Multiply(TWO, args[ind + args.length / 2]), v))),
- new Multiply(
- TWO,
- new Sqrt(new Sumsq(...firstHalf)
- )
- )
- )
- }
- );
- const Sumexp = newOperation(
- (...args) => args.reduce((a, b) => a + Math.exp(b), 0),
- "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]) / args.reduce((a, b) => a + Math.exp(b), 0),
- "softmax",
- (...args) => {
- let firstHalf = args.slice(0, args.length / 2);
- return new Divide(
- new Subtract(
- new Multiply(
- new Multiply(args[args.length / 2], new Sumexp(args[0])),
- new Sumexp(...firstHalf)),
- new Multiply(
- new Sumexp(args[0]),
- new Sum(...firstHalf.map(
- (v, ind) => new Multiply(args[ind + args.length / 2], new Sumexp(v))))
- )),
- new Multiply(
- new Sumexp(...firstHalf),
- new Sumexp(...firstHalf))
- )
- }
- );
- 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