IzhanVarsky

Untitled

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