Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- let expression = (function () {
- let exceptions = function () {
- let exceptionFactory = function (msg) {
- let Exception = function (idx, token) {
- this.name = msg + " on position " + idx + ", where '" + token + "' is";
- };
- Exception.prototype = Error.prototype;
- return Exception;
- };
- let ClosingParenthesisMissingException = exceptionFactory(
- 'Closing parenthesis expected'
- );
- let ExpressionEndExpectedException = exceptionFactory(
- 'End of expression expected'
- );
- let OperationExpectedException = exceptionFactory(
- 'Operation symbol expected'
- );
- let OperandExpectedException = exceptionFactory(
- 'Operand expected'
- );
- let EndOfConstantExpectedException = exceptionFactory(
- 'End of constant expected'
- );
- let InvalidOperandsAmountException = exceptionFactory(
- 'Invalid operands amount found'
- );
- return {
- ClosingParenthesisMissingException: ClosingParenthesisMissingException,
- ExpressionEndExpectedException: ExpressionEndExpectedException,
- OperationExpectedException: OperationExpectedException,
- OperandExpectedException: OperandExpectedException,
- EndOfConstantExpectedException: EndOfConstantExpectedException,
- InvalidOperandsAmountException: InvalidOperandsAmountException,
- }
- }();
- function Const(value) {
- this.value = value;
- }
- const ZERO = new Const(0);
- const ONE = new Const(1);
- Const.prototype.evaluate = function () {
- return this.value;
- };
- Const.prototype.toString = function () {
- return this.value.toString();
- };
- Const.prototype.prefix = Const.prototype.toString;
- Const.prototype.diff = function () {
- return ZERO;
- };
- const VARIABLES = {
- "x" : 0,
- "y" : 1,
- "z" : 2
- };
- function Variable(name) {
- this.name = name;
- }
- Variable.prototype.evaluate = function () {
- return arguments[VARIABLES[this.name]];
- };
- Variable.prototype.toString = function () {
- return this.name.toString();
- };
- Variable.prototype.prefix = Variable.prototype.toString;
- Variable.prototype.diff = function (name) {
- if (this.name === name) {
- return ONE;
- } else {
- return ZERO;
- }
- };
- function Operation() {
- this.operands = Array.from(arguments);
- this.getOperands = function() {
- return this.operands;
- }
- }
- Operation.prototype.prefix = function() {
- let operands = this.getOperands();
- let res = "(" + this.operationStr + ' ';
- for (let i = 0; i < operands.length - 1; i++) {
- res += operands[i].prefix();
- res += ' ';
- }
- if (operands.length > 0) {
- res += operands[operands.length - 1].prefix();
- }
- res += ')';
- return res;
- };
- Operation.prototype.evaluate = function (...args) {
- let result = [];
- this.getOperands().map(function (operand) {
- result.push(operand.evaluate(...args));
- });
- return this.doOperation(...result);
- };
- Operation.prototype.diff = function (name) {
- let args = [];
- this.getOperands().map(function (operand) {
- args.push(operand);
- args.push(operand.diff(name));
- });
- return this.doDiff(...args);
- };
- Operation.prototype.toString = function () {
- let res = "";
- this.getOperands().map(function (operand) {
- res += operand.toString() + ' ';
- });
- res += this.operationStr;
- return res;
- };
- function operationFactory(operationStr, doOperation, doDiff, doSimplify) {
- function Constructor() {
- Operation.apply(this, arguments);
- return this;
- }
- Constructor.prototype = Object.create(Operation.prototype);
- Constructor.prototype.operationStr = operationStr;
- Constructor.prototype.constructor = Constructor;
- Constructor.prototype.doOperation = doOperation;
- Constructor.prototype.doDiff = doDiff;
- return Constructor;
- }
- function checkZero(operand) {
- if (operand instanceof Const) {
- return operand.value === 0;
- }
- return false;
- }
- function checkOne(operand) {
- if (operand instanceof Const) {
- return operand.value === 1;
- }
- return false;
- }
- const Add = operationFactory('+',
- (x, y) => x + y,
- (x, dx, y, dy) => new Add(dx, dy));
- const Subtract = operationFactory('-',
- (x, y) => x - y,
- (x, dx, y, dy) => new Subtract(dx, dy));
- const Multiply = operationFactory('*',
- (x, y) => x * y,
- (x, dx, y, dy) => new Add(new Multiply(dx, y), new Multiply(dy, x)));
- const Divide = operationFactory('/',
- (x, y) => x / y,
- (x, dx, y, dy) => new Divide(new Subtract(new Multiply(dx, y), new Multiply(dy, x)), new Multiply(y, y)));
- const ArcTan = operationFactory('atan',
- (x) => Math.atan(x),
- (x, dx) => new Divide(dx, new Add(ONE, new Multiply(x, x))));
- const ArcTan2 = operationFactory('atan2',
- (x, y) => Math.atan2(x, y),
- (x, dx, y, dy) => new Divide(new Subtract(new Multiply(dx, y), new Multiply(dy, x)), new Add(new Multiply(y, y), new Multiply(x, x))));
- const Negate = operationFactory('negate', (x) => -x, (x, dx) => new Negate(dx));
- const Sum = operationFactory('sum',
- (...operands) => {
- let result = 0;
- for (let operand of operands) {
- result += operand;
- }
- return result;
- },
- (...operands) => {
- let arguments = [];
- for (let i = 1; i < operands.length; i += 2) {
- arguments.push(operands[i]);
- }
- return new Sum(...arguments);
- });
- const Sumexp = operationFactory('sumexp',
- function(...operands) {
- let result = 0;
- for (let operand of operands) {
- result += Math.pow(Math.E, operand);
- }
- return result;
- },
- function (...operands) {
- let arguments = [];
- for (let i = 1; i < operands.length; i += 2) {
- arguments.push(new Multiply(operands[i], new Sumexp(operands[i - 1])));
- }
- return new Sum(...arguments);
- });
- const Softmax = operationFactory('softmax',
- function (...operands) {
- let result = 0;
- for (let operand of operands) {
- result += Math.pow(Math.E, operand);
- }
- result = Math.pow(Math.E, operands[0]) / result;
- return result;
- },
- function (...operands) {
- let operandsx = [];
- for (let i = 0; i < operands.length; i += 2) {
- operandsx.push(operands[i]);
- }
- let operandsdx = [];
- for (let i = 1; i < operands.length; i += 2) {
- operandsdx.push(operands[i]);
- }
- let denominator = new Sumexp(...operandsx);
- let numerator = new Sumexp(operandsx[0]);
- let res = new Divide(numerator, denominator);
- return res.doDiff(numerator, numerator.doDiff(operandsx[0], operandsdx[0]), denominator, denominator.doDiff(...operands));
- });
- const CONSTANT = {
- "one" : 1,
- "two" : 2
- };
- const OPERATION = {
- "+" : Add,
- "-" : Subtract,
- "*" : Multiply,
- "/" : Divide,
- "negate": Negate,
- "atan": ArcTan,
- "atan2": ArcTan2,
- "sum": Sum,
- "sumexp": Sumexp,
- "softmax": Softmax
- };
- const CNT_ARGUMENTS = {
- "+" : 2,
- "-" : 2,
- "*" : 2,
- "/" : 2,
- "negate": 1,
- "atan": 1,
- "atan2": 2,
- "sum": null,
- "sumexp": null,
- "softmax": null
- };
- function parse(expr) {
- const tokens = expr.split(" ").filter(f => f.length > 0);
- let stack = [];
- tokens.map(function (token) {
- if (token in VARIABLES) {
- stack.push(new Variable(token));
- } else if (token in OPERATION) {
- let arguments = stack.slice(stack.length - CNT_ARGUMENTS[token], stack.length);
- stack.splice(stack.length - CNT_ARGUMENTS[token], CNT_ARGUMENTS[token]);
- stack.push(new OPERATION[token](...arguments));
- } else if (token in CONSTANT) {
- stack.push(new Const(CONSTANT[token]));
- } else {
- stack.push(new Const(Number(token)));
- }
- });
- return stack.pop();
- }
- let Tokenizer = function (expression) {
- this.pos = 0;
- this.prevToken = "";
- this.token = "";
- let isWhitespace = function (symbol) {
- return /[\s]/.test(symbol);
- };
- this.nextToken = function () {
- this.prevToken = this.token;
- while (this.pos < expression.length && isWhitespace(expression[this.pos])) {
- this.pos++;
- }
- this.token = "";
- if (expression[this.pos] === '(' || expression[this.pos] === ')') {
- this.token = expression[this.pos++];
- } else {
- while (this.pos < expression.length &&
- !isWhitespace(expression[this.pos]) && expression[this.pos] !== '(' && expression[this.pos] !== ')') {
- this.token += expression[this.pos++];
- }
- }
- };
- };
- let parseOperand = function (tokenizer, parseExpression) {
- if (tokenizer.token === '(') {
- return parseExpression();
- } else if (tokenizer.token in VARIABLES) {
- tokenizer.nextToken();
- return new Variable(tokenizer.prevToken);
- } else if (tokenizer.token !== '' && !isNaN(tokenizer.token)) {
- tokenizer.nextToken();
- return new Const(parseInt(tokenizer.prevToken));
- } else {
- throw new exceptions.OperandExpectedException(tokenizer.pos, tokenizer.token);
- }
- };
- let parsePrefix = function (expression) {
- let tokenizer = new Tokenizer(expression);
- let parseExpression = function () {
- if (tokenizer.token === '(') {
- tokenizer.nextToken();
- if (!(tokenizer.token in OPERATION)) {
- throw new exceptions.OperationExpectedException(tokenizer.pos, tokenizer.token);
- }
- let op = OPERATION[tokenizer.token];
- let cnt = CNT_ARGUMENTS[tokenizer.token];
- tokenizer.nextToken();
- let arguments = [];
- let i = 0;
- while (i !== cnt) {
- i++;
- if (cnt === null && tokenizer.token === ')') {
- break;
- }
- arguments.push(parseOperand(tokenizer, parseExpression));
- }
- if (tokenizer.token !== ')') {
- throw new exceptions.ClosingParenthesisMissingException(tokenizer.pos, tokenizer.token);
- }
- tokenizer.nextToken();
- return new op(...arguments);
- } else {
- return parseOperand(tokenizer, parseExpression);
- }
- };
- tokenizer.nextToken();
- let res = parseExpression();
- if (tokenizer.token !== "") {
- throw new exceptions.ExpressionEndExpectedException(tokenizer.pos, tokenizer.token);
- }
- return res;
- };
- return {
- "Const": Const,
- "Variable": Variable,
- "ArcTan": ArcTan,
- "ArcTan2": ArcTan2,
- "Negate": Negate,
- "Sum": Sum,
- "Sumexp": Sumexp,
- "Softmax": Softmax,
- "Add": Add,
- "Subtract": Subtract,
- "Multiply": Multiply,
- "Divide": Divide,
- "parse": parse,
- "parsePrefix": parsePrefix
- }
- })();
- let
- Const = expression.Const,
- Variable = expression.Variable,
- ArcTan = expression.ArcTan,
- Negate = expression.Negate,
- Add = expression.Add,
- Subtract = expression.Subtract,
- Multiply = expression.Multiply,
- Divide = expression.Divide,
- Sum = expression.Sum,
- Sumexp = expression.Sumexp,
- Softmax = expression.Softmax,
- parse = expression.parse,
- parsePrefix = expression.parsePrefix;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement