Advertisement
IzhanVarsky

Untitled

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