ndarray-ops.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. "use strict"
  2. var compile = require("cwise-compiler")
  3. var EmptyProc = {
  4. body: "",
  5. args: [],
  6. thisVars: [],
  7. localVars: []
  8. }
  9. function fixup(x) {
  10. if(!x) {
  11. return EmptyProc
  12. }
  13. for(var i=0; i<x.args.length; ++i) {
  14. var a = x.args[i]
  15. if(i === 0) {
  16. x.args[i] = {name: a, lvalue:true, rvalue: !!x.rvalue, count:x.count||1 }
  17. } else {
  18. x.args[i] = {name: a, lvalue:false, rvalue:true, count: 1}
  19. }
  20. }
  21. if(!x.thisVars) {
  22. x.thisVars = []
  23. }
  24. if(!x.localVars) {
  25. x.localVars = []
  26. }
  27. return x
  28. }
  29. function pcompile(user_args) {
  30. return compile({
  31. args: user_args.args,
  32. pre: fixup(user_args.pre),
  33. body: fixup(user_args.body),
  34. post: fixup(user_args.proc),
  35. funcName: user_args.funcName
  36. })
  37. }
  38. function makeOp(user_args) {
  39. var args = []
  40. for(var i=0; i<user_args.args.length; ++i) {
  41. args.push("a"+i)
  42. }
  43. var wrapper = new Function("P", [
  44. "return function ", user_args.funcName, "_ndarrayops(", args.join(","), ") {P(", args.join(","), ");return a0}"
  45. ].join(""))
  46. return wrapper(pcompile(user_args))
  47. }
  48. var assign_ops = {
  49. add: "+",
  50. sub: "-",
  51. mul: "*",
  52. div: "/",
  53. mod: "%",
  54. band: "&",
  55. bor: "|",
  56. bxor: "^",
  57. lshift: "<<",
  58. rshift: ">>",
  59. rrshift: ">>>"
  60. }
  61. ;(function(){
  62. for(var id in assign_ops) {
  63. var op = assign_ops[id]
  64. exports[id] = makeOp({
  65. args: ["array","array","array"],
  66. body: {args:["a","b","c"],
  67. body: "a=b"+op+"c"},
  68. funcName: id
  69. })
  70. exports[id+"eq"] = makeOp({
  71. args: ["array","array"],
  72. body: {args:["a","b"],
  73. body:"a"+op+"=b"},
  74. rvalue: true,
  75. funcName: id+"eq"
  76. })
  77. exports[id+"s"] = makeOp({
  78. args: ["array", "array", "scalar"],
  79. body: {args:["a","b","s"],
  80. body:"a=b"+op+"s"},
  81. funcName: id+"s"
  82. })
  83. exports[id+"seq"] = makeOp({
  84. args: ["array","scalar"],
  85. body: {args:["a","s"],
  86. body:"a"+op+"=s"},
  87. rvalue: true,
  88. funcName: id+"seq"
  89. })
  90. }
  91. })();
  92. var unary_ops = {
  93. not: "!",
  94. bnot: "~",
  95. neg: "-",
  96. recip: "1.0/"
  97. }
  98. ;(function(){
  99. for(var id in unary_ops) {
  100. var op = unary_ops[id]
  101. exports[id] = makeOp({
  102. args: ["array", "array"],
  103. body: {args:["a","b"],
  104. body:"a="+op+"b"},
  105. funcName: id
  106. })
  107. exports[id+"eq"] = makeOp({
  108. args: ["array"],
  109. body: {args:["a"],
  110. body:"a="+op+"a"},
  111. rvalue: true,
  112. count: 2,
  113. funcName: id+"eq"
  114. })
  115. }
  116. })();
  117. var binary_ops = {
  118. and: "&&",
  119. or: "||",
  120. eq: "===",
  121. neq: "!==",
  122. lt: "<",
  123. gt: ">",
  124. leq: "<=",
  125. geq: ">="
  126. }
  127. ;(function() {
  128. for(var id in binary_ops) {
  129. var op = binary_ops[id]
  130. exports[id] = makeOp({
  131. args: ["array","array","array"],
  132. body: {args:["a", "b", "c"],
  133. body:"a=b"+op+"c"},
  134. funcName: id
  135. })
  136. exports[id+"s"] = makeOp({
  137. args: ["array","array","scalar"],
  138. body: {args:["a", "b", "s"],
  139. body:"a=b"+op+"s"},
  140. funcName: id+"s"
  141. })
  142. exports[id+"eq"] = makeOp({
  143. args: ["array", "array"],
  144. body: {args:["a", "b"],
  145. body:"a=a"+op+"b"},
  146. rvalue:true,
  147. count:2,
  148. funcName: id+"eq"
  149. })
  150. exports[id+"seq"] = makeOp({
  151. args: ["array", "scalar"],
  152. body: {args:["a","s"],
  153. body:"a=a"+op+"s"},
  154. rvalue:true,
  155. count:2,
  156. funcName: id+"seq"
  157. })
  158. }
  159. })();
  160. var math_unary = [
  161. "abs",
  162. "acos",
  163. "asin",
  164. "atan",
  165. "ceil",
  166. "cos",
  167. "exp",
  168. "floor",
  169. "log",
  170. "round",
  171. "sin",
  172. "sqrt",
  173. "tan"
  174. ]
  175. ;(function() {
  176. for(var i=0; i<math_unary.length; ++i) {
  177. var f = math_unary[i]
  178. exports[f] = makeOp({
  179. args: ["array", "array"],
  180. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  181. body: {args:["a","b"], body:"a=this_f(b)", thisVars:["this_f"]},
  182. funcName: f
  183. })
  184. exports[f+"eq"] = makeOp({
  185. args: ["array"],
  186. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  187. body: {args: ["a"], body:"a=this_f(a)", thisVars:["this_f"]},
  188. rvalue: true,
  189. count: 2,
  190. funcName: f+"eq"
  191. })
  192. }
  193. })();
  194. var math_comm = [
  195. "max",
  196. "min",
  197. "atan2",
  198. "pow"
  199. ]
  200. ;(function(){
  201. for(var i=0; i<math_comm.length; ++i) {
  202. var f= math_comm[i]
  203. exports[f] = makeOp({
  204. args:["array", "array", "array"],
  205. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  206. body: {args:["a","b","c"], body:"a=this_f(b,c)", thisVars:["this_f"]},
  207. funcName: f
  208. })
  209. exports[f+"s"] = makeOp({
  210. args:["array", "array", "scalar"],
  211. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  212. body: {args:["a","b","c"], body:"a=this_f(b,c)", thisVars:["this_f"]},
  213. funcName: f+"s"
  214. })
  215. exports[f+"eq"] = makeOp({ args:["array", "array"],
  216. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  217. body: {args:["a","b"], body:"a=this_f(a,b)", thisVars:["this_f"]},
  218. rvalue: true,
  219. count: 2,
  220. funcName: f+"eq"
  221. })
  222. exports[f+"seq"] = makeOp({ args:["array", "scalar"],
  223. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  224. body: {args:["a","b"], body:"a=this_f(a,b)", thisVars:["this_f"]},
  225. rvalue:true,
  226. count:2,
  227. funcName: f+"seq"
  228. })
  229. }
  230. })();
  231. var math_noncomm = [
  232. "atan2",
  233. "pow"
  234. ]
  235. ;(function(){
  236. for(var i=0; i<math_noncomm.length; ++i) {
  237. var f= math_noncomm[i]
  238. exports[f+"op"] = makeOp({
  239. args:["array", "array", "array"],
  240. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  241. body: {args:["a","b","c"], body:"a=this_f(c,b)", thisVars:["this_f"]},
  242. funcName: f+"op"
  243. })
  244. exports[f+"ops"] = makeOp({
  245. args:["array", "array", "scalar"],
  246. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  247. body: {args:["a","b","c"], body:"a=this_f(c,b)", thisVars:["this_f"]},
  248. funcName: f+"ops"
  249. })
  250. exports[f+"opeq"] = makeOp({ args:["array", "array"],
  251. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  252. body: {args:["a","b"], body:"a=this_f(b,a)", thisVars:["this_f"]},
  253. rvalue: true,
  254. count: 2,
  255. funcName: f+"opeq"
  256. })
  257. exports[f+"opseq"] = makeOp({ args:["array", "scalar"],
  258. pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]},
  259. body: {args:["a","b"], body:"a=this_f(b,a)", thisVars:["this_f"]},
  260. rvalue:true,
  261. count:2,
  262. funcName: f+"opseq"
  263. })
  264. }
  265. })();
  266. exports.any = compile({
  267. args:["array"],
  268. pre: EmptyProc,
  269. body: {args:[{name:"a", lvalue:false, rvalue:true, count:1}], body: "if(a){return true}", localVars: [], thisVars: []},
  270. post: {args:[], localVars:[], thisVars:[], body:"return false"},
  271. funcName: "any"
  272. })
  273. exports.all = compile({
  274. args:["array"],
  275. pre: EmptyProc,
  276. body: {args:[{name:"x", lvalue:false, rvalue:true, count:1}], body: "if(!x){return false}", localVars: [], thisVars: []},
  277. post: {args:[], localVars:[], thisVars:[], body:"return true"},
  278. funcName: "all"
  279. })
  280. exports.sum = compile({
  281. args:["array"],
  282. pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"},
  283. body: {args:[{name:"a", lvalue:false, rvalue:true, count:1}], body: "this_s+=a", localVars: [], thisVars: ["this_s"]},
  284. post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"},
  285. funcName: "sum"
  286. })
  287. exports.prod = compile({
  288. args:["array"],
  289. pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=1"},
  290. body: {args:[{name:"a", lvalue:false, rvalue:true, count:1}], body: "this_s*=a", localVars: [], thisVars: ["this_s"]},
  291. post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"},
  292. funcName: "prod"
  293. })
  294. exports.norm2squared = compile({
  295. args:["array"],
  296. pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"},
  297. body: {args:[{name:"a", lvalue:false, rvalue:true, count:2}], body: "this_s+=a*a", localVars: [], thisVars: ["this_s"]},
  298. post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"},
  299. funcName: "norm2squared"
  300. })
  301. exports.norm2 = compile({
  302. args:["array"],
  303. pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"},
  304. body: {args:[{name:"a", lvalue:false, rvalue:true, count:2}], body: "this_s+=a*a", localVars: [], thisVars: ["this_s"]},
  305. post: {args:[], localVars:[], thisVars:["this_s"], body:"return Math.sqrt(this_s)"},
  306. funcName: "norm2"
  307. })
  308. exports.norminf = compile({
  309. args:["array"],
  310. pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"},
  311. body: {args:[{name:"a", lvalue:false, rvalue:true, count:4}], body:"if(-a>this_s){this_s=-a}else if(a>this_s){this_s=a}", localVars: [], thisVars: ["this_s"]},
  312. post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"},
  313. funcName: "norminf"
  314. })
  315. exports.norm1 = compile({
  316. args:["array"],
  317. pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"},
  318. body: {args:[{name:"a", lvalue:false, rvalue:true, count:3}], body: "this_s+=a<0?-a:a", localVars: [], thisVars: ["this_s"]},
  319. post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"},
  320. funcName: "norm1"
  321. })
  322. exports.sup = compile({
  323. args: [ "array" ],
  324. pre:
  325. { body: "this_h=-Infinity",
  326. args: [],
  327. thisVars: [ "this_h" ],
  328. localVars: [] },
  329. body:
  330. { body: "if(_inline_1_arg0_>this_h)this_h=_inline_1_arg0_",
  331. args: [{"name":"_inline_1_arg0_","lvalue":false,"rvalue":true,"count":2} ],
  332. thisVars: [ "this_h" ],
  333. localVars: [] },
  334. post:
  335. { body: "return this_h",
  336. args: [],
  337. thisVars: [ "this_h" ],
  338. localVars: [] }
  339. })
  340. exports.inf = compile({
  341. args: [ "array" ],
  342. pre:
  343. { body: "this_h=Infinity",
  344. args: [],
  345. thisVars: [ "this_h" ],
  346. localVars: [] },
  347. body:
  348. { body: "if(_inline_1_arg0_<this_h)this_h=_inline_1_arg0_",
  349. args: [{"name":"_inline_1_arg0_","lvalue":false,"rvalue":true,"count":2} ],
  350. thisVars: [ "this_h" ],
  351. localVars: [] },
  352. post:
  353. { body: "return this_h",
  354. args: [],
  355. thisVars: [ "this_h" ],
  356. localVars: [] }
  357. })
  358. exports.argmin = compile({
  359. args:["index","array","shape"],
  360. pre:{
  361. body:"{this_v=Infinity;this_i=_inline_0_arg2_.slice(0)}",
  362. args:[
  363. {name:"_inline_0_arg0_",lvalue:false,rvalue:false,count:0},
  364. {name:"_inline_0_arg1_",lvalue:false,rvalue:false,count:0},
  365. {name:"_inline_0_arg2_",lvalue:false,rvalue:true,count:1}
  366. ],
  367. thisVars:["this_i","this_v"],
  368. localVars:[]},
  369. body:{
  370. body:"{if(_inline_1_arg1_<this_v){this_v=_inline_1_arg1_;for(var _inline_1_k=0;_inline_1_k<_inline_1_arg0_.length;++_inline_1_k){this_i[_inline_1_k]=_inline_1_arg0_[_inline_1_k]}}}",
  371. args:[
  372. {name:"_inline_1_arg0_",lvalue:false,rvalue:true,count:2},
  373. {name:"_inline_1_arg1_",lvalue:false,rvalue:true,count:2}],
  374. thisVars:["this_i","this_v"],
  375. localVars:["_inline_1_k"]},
  376. post:{
  377. body:"{return this_i}",
  378. args:[],
  379. thisVars:["this_i"],
  380. localVars:[]}
  381. })
  382. exports.argmax = compile({
  383. args:["index","array","shape"],
  384. pre:{
  385. body:"{this_v=-Infinity;this_i=_inline_0_arg2_.slice(0)}",
  386. args:[
  387. {name:"_inline_0_arg0_",lvalue:false,rvalue:false,count:0},
  388. {name:"_inline_0_arg1_",lvalue:false,rvalue:false,count:0},
  389. {name:"_inline_0_arg2_",lvalue:false,rvalue:true,count:1}
  390. ],
  391. thisVars:["this_i","this_v"],
  392. localVars:[]},
  393. body:{
  394. body:"{if(_inline_1_arg1_>this_v){this_v=_inline_1_arg1_;for(var _inline_1_k=0;_inline_1_k<_inline_1_arg0_.length;++_inline_1_k){this_i[_inline_1_k]=_inline_1_arg0_[_inline_1_k]}}}",
  395. args:[
  396. {name:"_inline_1_arg0_",lvalue:false,rvalue:true,count:2},
  397. {name:"_inline_1_arg1_",lvalue:false,rvalue:true,count:2}],
  398. thisVars:["this_i","this_v"],
  399. localVars:["_inline_1_k"]},
  400. post:{
  401. body:"{return this_i}",
  402. args:[],
  403. thisVars:["this_i"],
  404. localVars:[]}
  405. })
  406. exports.random = makeOp({
  407. args: ["array"],
  408. pre: {args:[], body:"this_f=Math.random", thisVars:["this_f"]},
  409. body: {args: ["a"], body:"a=this_f()", thisVars:["this_f"]},
  410. funcName: "random"
  411. })
  412. exports.assign = makeOp({
  413. args:["array", "array"],
  414. body: {args:["a", "b"], body:"a=b"},
  415. funcName: "assign" })
  416. exports.assigns = makeOp({
  417. args:["array", "scalar"],
  418. body: {args:["a", "b"], body:"a=b"},
  419. funcName: "assigns" })
  420. exports.equals = compile({
  421. args:["array", "array"],
  422. pre: EmptyProc,
  423. body: {args:[{name:"x", lvalue:false, rvalue:true, count:1},
  424. {name:"y", lvalue:false, rvalue:true, count:1}],
  425. body: "if(x!==y){return false}",
  426. localVars: [],
  427. thisVars: []},
  428. post: {args:[], localVars:[], thisVars:[], body:"return true"},
  429. funcName: "equals"
  430. })