oakscriptjs 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +31 -9
  3. package/dist/cjs/array/index.d.ts +701 -0
  4. package/dist/cjs/array/index.d.ts.map +1 -0
  5. package/dist/cjs/array/index.js +392 -0
  6. package/dist/cjs/array/index.js.map +7 -0
  7. package/dist/cjs/box/index.d.ts +444 -0
  8. package/dist/cjs/box/index.d.ts.map +1 -0
  9. package/dist/cjs/box/index.js +246 -0
  10. package/dist/cjs/box/index.js.map +7 -0
  11. package/dist/cjs/callsite/index.d.ts +61 -0
  12. package/dist/cjs/callsite/index.d.ts.map +1 -0
  13. package/dist/cjs/callsite/index.js +65 -0
  14. package/dist/cjs/callsite/index.js.map +7 -0
  15. package/dist/cjs/chartpoint/index.d.ts +90 -0
  16. package/dist/cjs/chartpoint/index.d.ts.map +1 -0
  17. package/dist/cjs/chartpoint/index.js +56 -0
  18. package/dist/cjs/chartpoint/index.js.map +7 -0
  19. package/dist/cjs/color/index.d.ts +285 -0
  20. package/dist/cjs/color/index.d.ts.map +1 -0
  21. package/dist/cjs/color/index.js +143 -0
  22. package/dist/cjs/color/index.js.map +7 -0
  23. package/dist/cjs/compare/index.d.ts +26 -0
  24. package/dist/cjs/compare/index.d.ts.map +1 -0
  25. package/dist/cjs/compare/index.js +50 -0
  26. package/dist/cjs/compare/index.js.map +7 -0
  27. package/dist/cjs/drawing/registry.d.ts +42 -0
  28. package/dist/cjs/drawing/registry.d.ts.map +1 -0
  29. package/dist/cjs/drawing/registry.js +87 -0
  30. package/dist/cjs/drawing/registry.js.map +7 -0
  31. package/dist/cjs/index.d.ts +85 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +184 -0
  34. package/dist/cjs/index.js.map +7 -0
  35. package/dist/cjs/indicator.d.ts +117 -0
  36. package/dist/cjs/indicator.d.ts.map +1 -0
  37. package/dist/cjs/indicator.js +74 -0
  38. package/dist/cjs/indicator.js.map +7 -0
  39. package/dist/cjs/input.d.ts +196 -0
  40. package/dist/cjs/input.d.ts.map +1 -0
  41. package/dist/cjs/input.js +197 -0
  42. package/dist/cjs/input.js.map +7 -0
  43. package/dist/cjs/label/index.d.ts +303 -0
  44. package/dist/cjs/label/index.d.ts.map +1 -0
  45. package/dist/cjs/label/index.js +190 -0
  46. package/dist/cjs/label/index.js.map +7 -0
  47. package/dist/cjs/lib/index.d.ts +8 -0
  48. package/dist/cjs/lib/index.d.ts.map +1 -0
  49. package/dist/cjs/lib/index.js +19 -0
  50. package/dist/cjs/lib/index.js.map +7 -0
  51. package/dist/{lib → cjs/lib}/zigzag/index.d.ts +4 -1
  52. package/dist/cjs/lib/zigzag/index.d.ts.map +1 -0
  53. package/dist/cjs/lib/zigzag/index.js +27 -0
  54. package/dist/cjs/lib/zigzag/index.js.map +7 -0
  55. package/dist/cjs/lib/zigzag/zigzag.d.ts +100 -0
  56. package/dist/cjs/lib/zigzag/zigzag.d.ts.map +1 -0
  57. package/dist/cjs/lib/zigzag/zigzag.js +207 -0
  58. package/dist/cjs/lib/zigzag/zigzag.js.map +7 -0
  59. package/dist/cjs/line/index.d.ts +342 -0
  60. package/dist/cjs/line/index.d.ts.map +1 -0
  61. package/dist/cjs/line/index.js +193 -0
  62. package/dist/cjs/line/index.js.map +7 -0
  63. package/dist/cjs/linefill/index.d.ts +124 -0
  64. package/dist/cjs/linefill/index.d.ts.map +1 -0
  65. package/dist/cjs/linefill/index.js +56 -0
  66. package/dist/cjs/linefill/index.js.map +7 -0
  67. package/dist/cjs/map/index.d.ts +69 -0
  68. package/dist/cjs/map/index.d.ts.map +1 -0
  69. package/dist/cjs/map/index.js +80 -0
  70. package/dist/cjs/map/index.js.map +7 -0
  71. package/dist/cjs/math/index.d.ts +560 -0
  72. package/dist/cjs/math/index.d.ts.map +1 -0
  73. package/dist/cjs/math/index.js +441 -0
  74. package/dist/cjs/math/index.js.map +7 -0
  75. package/dist/cjs/matrix/index.d.ts +1231 -0
  76. package/dist/cjs/matrix/index.d.ts.map +1 -0
  77. package/dist/cjs/matrix/index.js +1200 -0
  78. package/dist/cjs/matrix/index.js.map +7 -0
  79. package/dist/cjs/package.json +1 -0
  80. package/dist/cjs/plot.d.ts +76 -0
  81. package/dist/cjs/plot.d.ts.map +1 -0
  82. package/dist/cjs/plot.js +51 -0
  83. package/dist/cjs/plot.js.map +7 -0
  84. package/dist/cjs/polyline/index.d.ts +115 -0
  85. package/dist/cjs/polyline/index.d.ts.map +1 -0
  86. package/dist/cjs/polyline/index.js +76 -0
  87. package/dist/cjs/polyline/index.js.map +7 -0
  88. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.d.ts +86 -0
  89. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.d.ts.map +1 -0
  90. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.js +141 -0
  91. package/dist/cjs/runtime/adapters/LightweightChartsAdapter.js.map +7 -0
  92. package/dist/cjs/runtime/adapters/SimpleInputAdapter.d.ts +59 -0
  93. package/dist/cjs/runtime/adapters/SimpleInputAdapter.d.ts.map +1 -0
  94. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js +117 -0
  95. package/dist/cjs/runtime/adapters/SimpleInputAdapter.js.map +7 -0
  96. package/dist/{runtime → cjs/runtime}/index.d.ts +12 -5
  97. package/dist/cjs/runtime/index.d.ts.map +1 -0
  98. package/dist/cjs/runtime/index.js +49 -0
  99. package/dist/cjs/runtime/index.js.map +7 -0
  100. package/dist/cjs/runtime/inputs.d.ts +91 -0
  101. package/dist/cjs/runtime/inputs.d.ts.map +1 -0
  102. package/dist/cjs/runtime/inputs.js +262 -0
  103. package/dist/cjs/runtime/inputs.js.map +7 -0
  104. package/dist/cjs/runtime/runtime.d.ts +70 -0
  105. package/dist/cjs/runtime/runtime.d.ts.map +1 -0
  106. package/dist/cjs/runtime/runtime.js +148 -0
  107. package/dist/cjs/runtime/runtime.js.map +7 -0
  108. package/dist/cjs/runtime/series.d.ts +362 -0
  109. package/dist/cjs/runtime/series.d.ts.map +1 -0
  110. package/dist/cjs/runtime/series.js +560 -0
  111. package/dist/cjs/runtime/series.js.map +7 -0
  112. package/dist/cjs/runtime/types.d.ts +282 -0
  113. package/dist/cjs/runtime/types.d.ts.map +1 -0
  114. package/dist/cjs/runtime/types.js +17 -0
  115. package/dist/cjs/runtime/types.js.map +7 -0
  116. package/dist/cjs/script/index.d.ts +987 -0
  117. package/dist/cjs/script/index.d.ts.map +1 -0
  118. package/dist/cjs/script/index.js +1169 -0
  119. package/dist/cjs/script/index.js.map +7 -0
  120. package/dist/cjs/security/resample.d.ts +63 -0
  121. package/dist/cjs/security/resample.d.ts.map +1 -0
  122. package/dist/cjs/security/resample.js +84 -0
  123. package/dist/cjs/security/resample.js.map +7 -0
  124. package/dist/cjs/session/bars.d.ts +80 -0
  125. package/dist/cjs/session/bars.d.ts.map +1 -0
  126. package/dist/cjs/session/bars.js +219 -0
  127. package/dist/cjs/session/bars.js.map +7 -0
  128. package/dist/cjs/session/calendar.d.ts +70 -0
  129. package/dist/cjs/session/calendar.d.ts.map +1 -0
  130. package/dist/cjs/session/calendar.js +164 -0
  131. package/dist/cjs/session/calendar.js.map +7 -0
  132. package/dist/cjs/str/dateformat.d.ts +15 -0
  133. package/dist/cjs/str/dateformat.d.ts.map +1 -0
  134. package/dist/cjs/str/dateformat.js +149 -0
  135. package/dist/cjs/str/dateformat.js.map +7 -0
  136. package/dist/cjs/str/index.d.ts +459 -0
  137. package/dist/cjs/str/index.d.ts.map +1 -0
  138. package/dist/cjs/str/index.js +143 -0
  139. package/dist/cjs/str/index.js.map +7 -0
  140. package/dist/cjs/str/messageformat.d.ts +14 -0
  141. package/dist/cjs/str/messageformat.d.ts.map +1 -0
  142. package/dist/cjs/str/messageformat.js +114 -0
  143. package/dist/cjs/str/messageformat.js.map +7 -0
  144. package/dist/cjs/str/numberformat.d.ts +19 -0
  145. package/dist/cjs/str/numberformat.d.ts.map +1 -0
  146. package/dist/cjs/str/numberformat.js +170 -0
  147. package/dist/cjs/str/numberformat.js.map +7 -0
  148. package/dist/{strategy → cjs/strategy}/index.d.ts +50 -0
  149. package/dist/cjs/strategy/index.d.ts.map +1 -0
  150. package/dist/cjs/strategy/index.js +92 -0
  151. package/dist/cjs/strategy/index.js.map +7 -0
  152. package/dist/cjs/ta/index.d.ts +1397 -0
  153. package/dist/cjs/ta/index.d.ts.map +1 -0
  154. package/dist/cjs/ta/index.js +1715 -0
  155. package/dist/cjs/ta/index.js.map +7 -0
  156. package/dist/cjs/ta/running-sum.d.ts +30 -0
  157. package/dist/cjs/ta/running-sum.d.ts.map +1 -0
  158. package/dist/cjs/ta/running-sum.js +99 -0
  159. package/dist/cjs/ta/running-sum.js.map +7 -0
  160. package/dist/cjs/ta-series.d.ts +558 -0
  161. package/dist/cjs/ta-series.d.ts.map +1 -0
  162. package/dist/cjs/ta-series.js +606 -0
  163. package/dist/cjs/ta-series.js.map +7 -0
  164. package/dist/cjs/text/index.d.ts +14 -0
  165. package/dist/cjs/text/index.d.ts.map +1 -0
  166. package/dist/cjs/text/index.js +29 -0
  167. package/dist/cjs/text/index.js.map +7 -0
  168. package/dist/cjs/time/datestring.d.ts +23 -0
  169. package/dist/cjs/time/datestring.d.ts.map +1 -0
  170. package/dist/cjs/time/datestring.js +106 -0
  171. package/dist/cjs/time/datestring.js.map +7 -0
  172. package/dist/cjs/time/index.d.ts +89 -0
  173. package/dist/cjs/time/index.d.ts.map +1 -0
  174. package/dist/cjs/time/index.js +85 -0
  175. package/dist/cjs/time/index.js.map +7 -0
  176. package/dist/cjs/time/session.d.ts +17 -0
  177. package/dist/cjs/time/session.d.ts.map +1 -0
  178. package/dist/cjs/time/session.js +65 -0
  179. package/dist/cjs/time/session.js.map +7 -0
  180. package/dist/cjs/time/timezone.d.ts +40 -0
  181. package/dist/cjs/time/timezone.d.ts.map +1 -0
  182. package/dist/cjs/time/timezone.js +125 -0
  183. package/dist/cjs/time/timezone.js.map +7 -0
  184. package/dist/cjs/timeframe/index.d.ts +73 -0
  185. package/dist/cjs/timeframe/index.d.ts.map +1 -0
  186. package/dist/cjs/timeframe/index.js +85 -0
  187. package/dist/cjs/timeframe/index.js.map +7 -0
  188. package/dist/cjs/types/index.d.ts +343 -0
  189. package/dist/cjs/types/index.d.ts.map +1 -0
  190. package/dist/cjs/types/index.js +32 -0
  191. package/dist/cjs/types/index.js.map +7 -0
  192. package/dist/cjs/types/metadata.d.ts +300 -0
  193. package/dist/cjs/types/metadata.d.ts.map +1 -0
  194. package/dist/cjs/types/metadata.js +17 -0
  195. package/dist/cjs/types/metadata.js.map +7 -0
  196. package/dist/cjs/utils/index.d.ts +167 -0
  197. package/dist/cjs/utils/index.d.ts.map +1 -0
  198. package/dist/cjs/utils/index.js +209 -0
  199. package/dist/cjs/utils/index.js.map +7 -0
  200. package/dist/esm/array/index.d.ts +701 -0
  201. package/dist/esm/array/index.d.ts.map +1 -0
  202. package/dist/esm/array/index.js +983 -0
  203. package/dist/esm/array/index.js.map +1 -0
  204. package/dist/esm/box/index.d.ts +444 -0
  205. package/dist/esm/box/index.d.ts.map +1 -0
  206. package/dist/esm/box/index.js +602 -0
  207. package/dist/esm/box/index.js.map +1 -0
  208. package/dist/esm/callsite/index.d.ts +61 -0
  209. package/dist/esm/callsite/index.d.ts.map +1 -0
  210. package/dist/esm/callsite/index.js +97 -0
  211. package/dist/esm/callsite/index.js.map +1 -0
  212. package/dist/esm/chartpoint/index.d.ts +90 -0
  213. package/dist/esm/chartpoint/index.d.ts.map +1 -0
  214. package/dist/esm/chartpoint/index.js +113 -0
  215. package/dist/esm/chartpoint/index.js.map +1 -0
  216. package/dist/esm/color/index.d.ts +285 -0
  217. package/dist/esm/color/index.d.ts.map +1 -0
  218. package/dist/esm/color/index.js +373 -0
  219. package/dist/esm/color/index.js.map +1 -0
  220. package/dist/esm/compare/index.d.ts +26 -0
  221. package/dist/esm/compare/index.d.ts.map +1 -0
  222. package/dist/esm/compare/index.js +39 -0
  223. package/dist/esm/compare/index.js.map +1 -0
  224. package/dist/esm/drawing/registry.d.ts +42 -0
  225. package/dist/esm/drawing/registry.d.ts.map +1 -0
  226. package/dist/esm/drawing/registry.js +89 -0
  227. package/dist/esm/drawing/registry.js.map +1 -0
  228. package/dist/esm/index.d.ts +85 -0
  229. package/dist/esm/index.d.ts.map +1 -0
  230. package/dist/esm/index.js +96 -0
  231. package/dist/esm/index.js.map +1 -0
  232. package/dist/esm/indicator.d.ts +117 -0
  233. package/dist/esm/indicator.d.ts.map +1 -0
  234. package/dist/esm/indicator.js +84 -0
  235. package/dist/esm/indicator.js.map +1 -0
  236. package/dist/esm/input.d.ts +196 -0
  237. package/dist/esm/input.d.ts.map +1 -0
  238. package/dist/esm/input.js +183 -0
  239. package/dist/esm/input.js.map +1 -0
  240. package/dist/esm/label/index.d.ts +303 -0
  241. package/dist/esm/label/index.d.ts.map +1 -0
  242. package/dist/esm/label/index.js +417 -0
  243. package/dist/esm/label/index.js.map +1 -0
  244. package/dist/esm/lib/index.d.ts +8 -0
  245. package/dist/esm/lib/index.d.ts.map +1 -0
  246. package/dist/esm/lib/index.js +8 -0
  247. package/dist/esm/lib/index.js.map +1 -0
  248. package/dist/esm/lib/zigzag/index.d.ts +5 -0
  249. package/dist/esm/lib/zigzag/index.d.ts.map +1 -0
  250. package/dist/esm/lib/zigzag/index.js +5 -0
  251. package/dist/esm/lib/zigzag/index.js.map +1 -0
  252. package/dist/esm/lib/zigzag/zigzag.d.ts +100 -0
  253. package/dist/esm/lib/zigzag/zigzag.d.ts.map +1 -0
  254. package/dist/esm/lib/zigzag/zigzag.js +229 -0
  255. package/dist/esm/lib/zigzag/zigzag.js.map +1 -0
  256. package/dist/esm/line/index.d.ts +342 -0
  257. package/dist/esm/line/index.d.ts.map +1 -0
  258. package/dist/esm/line/index.js +470 -0
  259. package/dist/esm/line/index.js.map +1 -0
  260. package/dist/esm/linefill/index.d.ts +124 -0
  261. package/dist/esm/linefill/index.d.ts.map +1 -0
  262. package/dist/esm/linefill/index.js +144 -0
  263. package/dist/esm/linefill/index.js.map +1 -0
  264. package/dist/esm/map/index.d.ts +69 -0
  265. package/dist/esm/map/index.d.ts.map +1 -0
  266. package/dist/esm/map/index.js +106 -0
  267. package/dist/esm/map/index.js.map +1 -0
  268. package/dist/esm/math/index.d.ts +560 -0
  269. package/dist/esm/math/index.d.ts.map +1 -0
  270. package/dist/esm/math/index.js +495 -0
  271. package/dist/esm/math/index.js.map +1 -0
  272. package/dist/esm/matrix/index.d.ts +1231 -0
  273. package/dist/esm/matrix/index.d.ts.map +1 -0
  274. package/dist/esm/matrix/index.js +2450 -0
  275. package/dist/esm/matrix/index.js.map +1 -0
  276. package/dist/esm/plot.d.ts +76 -0
  277. package/dist/esm/plot.d.ts.map +1 -0
  278. package/dist/esm/plot.js +63 -0
  279. package/dist/esm/plot.js.map +1 -0
  280. package/dist/esm/polyline/index.d.ts +115 -0
  281. package/dist/esm/polyline/index.d.ts.map +1 -0
  282. package/dist/esm/polyline/index.js +157 -0
  283. package/dist/esm/polyline/index.js.map +1 -0
  284. package/dist/esm/runtime/adapters/LightweightChartsAdapter.d.ts +86 -0
  285. package/dist/esm/runtime/adapters/LightweightChartsAdapter.d.ts.map +1 -0
  286. package/dist/esm/runtime/adapters/LightweightChartsAdapter.js +140 -0
  287. package/dist/esm/runtime/adapters/LightweightChartsAdapter.js.map +1 -0
  288. package/dist/esm/runtime/adapters/SimpleInputAdapter.d.ts +59 -0
  289. package/dist/esm/runtime/adapters/SimpleInputAdapter.d.ts.map +1 -0
  290. package/dist/esm/runtime/adapters/SimpleInputAdapter.js +115 -0
  291. package/dist/esm/runtime/adapters/SimpleInputAdapter.js.map +1 -0
  292. package/dist/esm/runtime/index.d.ts +13 -0
  293. package/dist/esm/runtime/index.d.ts.map +1 -0
  294. package/dist/esm/runtime/index.js +14 -0
  295. package/dist/esm/runtime/index.js.map +1 -0
  296. package/dist/esm/runtime/inputs.d.ts +91 -0
  297. package/dist/esm/runtime/inputs.d.ts.map +1 -0
  298. package/dist/esm/runtime/inputs.js +334 -0
  299. package/dist/esm/runtime/inputs.js.map +1 -0
  300. package/dist/esm/runtime/runtime.d.ts +70 -0
  301. package/dist/esm/runtime/runtime.d.ts.map +1 -0
  302. package/dist/esm/runtime/runtime.js +193 -0
  303. package/dist/esm/runtime/runtime.js.map +1 -0
  304. package/dist/esm/runtime/series.d.ts +362 -0
  305. package/dist/esm/runtime/series.d.ts.map +1 -0
  306. package/dist/esm/runtime/series.js +583 -0
  307. package/dist/esm/runtime/series.js.map +1 -0
  308. package/dist/esm/runtime/types.d.ts +282 -0
  309. package/dist/esm/runtime/types.d.ts.map +1 -0
  310. package/dist/esm/runtime/types.js +7 -0
  311. package/dist/esm/runtime/types.js.map +1 -0
  312. package/dist/esm/script/index.d.ts +987 -0
  313. package/dist/esm/script/index.d.ts.map +1 -0
  314. package/dist/esm/script/index.js +1289 -0
  315. package/dist/esm/script/index.js.map +1 -0
  316. package/dist/esm/security/resample.d.ts +63 -0
  317. package/dist/esm/security/resample.d.ts.map +1 -0
  318. package/dist/esm/security/resample.js +110 -0
  319. package/dist/esm/security/resample.js.map +1 -0
  320. package/dist/esm/session/bars.d.ts +80 -0
  321. package/dist/esm/session/bars.d.ts.map +1 -0
  322. package/dist/esm/session/bars.js +232 -0
  323. package/dist/esm/session/bars.js.map +1 -0
  324. package/dist/esm/session/calendar.d.ts +70 -0
  325. package/dist/esm/session/calendar.d.ts.map +1 -0
  326. package/dist/esm/session/calendar.js +172 -0
  327. package/dist/esm/session/calendar.js.map +1 -0
  328. package/dist/esm/str/dateformat.d.ts +15 -0
  329. package/dist/esm/str/dateformat.d.ts.map +1 -0
  330. package/dist/esm/str/dateformat.js +136 -0
  331. package/dist/esm/str/dateformat.js.map +1 -0
  332. package/dist/esm/str/index.d.ts +459 -0
  333. package/dist/esm/str/index.d.ts.map +1 -0
  334. package/dist/esm/str/index.js +540 -0
  335. package/dist/esm/str/index.js.map +1 -0
  336. package/dist/esm/str/messageformat.d.ts +14 -0
  337. package/dist/esm/str/messageformat.d.ts.map +1 -0
  338. package/dist/esm/str/messageformat.js +111 -0
  339. package/dist/esm/str/messageformat.js.map +1 -0
  340. package/dist/esm/str/numberformat.d.ts +19 -0
  341. package/dist/esm/str/numberformat.d.ts.map +1 -0
  342. package/dist/esm/str/numberformat.js +189 -0
  343. package/dist/esm/str/numberformat.js.map +1 -0
  344. package/dist/esm/strategy/index.d.ts +245 -0
  345. package/dist/esm/strategy/index.d.ts.map +1 -0
  346. package/dist/esm/strategy/index.js +84 -0
  347. package/dist/esm/strategy/index.js.map +1 -0
  348. package/dist/esm/ta/index.d.ts +1397 -0
  349. package/dist/esm/ta/index.d.ts.map +1 -0
  350. package/dist/esm/ta/index.js +3227 -0
  351. package/dist/esm/ta/index.js.map +1 -0
  352. package/dist/esm/ta/running-sum.d.ts +30 -0
  353. package/dist/esm/ta/running-sum.d.ts.map +1 -0
  354. package/dist/esm/ta/running-sum.js +113 -0
  355. package/dist/esm/ta/running-sum.js.map +1 -0
  356. package/dist/esm/ta-series.d.ts +558 -0
  357. package/dist/esm/ta-series.d.ts.map +1 -0
  358. package/dist/esm/ta-series.js +910 -0
  359. package/dist/esm/ta-series.js.map +1 -0
  360. package/dist/esm/text/index.d.ts +14 -0
  361. package/dist/esm/text/index.d.ts.map +1 -0
  362. package/dist/esm/text/index.js +14 -0
  363. package/dist/esm/text/index.js.map +1 -0
  364. package/dist/esm/time/datestring.d.ts +23 -0
  365. package/dist/esm/time/datestring.d.ts.map +1 -0
  366. package/dist/esm/time/datestring.js +94 -0
  367. package/dist/esm/time/datestring.js.map +1 -0
  368. package/dist/esm/time/index.d.ts +89 -0
  369. package/dist/esm/time/index.d.ts.map +1 -0
  370. package/dist/esm/time/index.js +108 -0
  371. package/dist/esm/time/index.js.map +1 -0
  372. package/dist/esm/time/session.d.ts +17 -0
  373. package/dist/esm/time/session.d.ts.map +1 -0
  374. package/dist/esm/time/session.js +69 -0
  375. package/dist/esm/time/session.js.map +1 -0
  376. package/dist/esm/time/timezone.d.ts +40 -0
  377. package/dist/esm/time/timezone.d.ts.map +1 -0
  378. package/dist/esm/time/timezone.js +144 -0
  379. package/dist/esm/time/timezone.js.map +1 -0
  380. package/dist/esm/timeframe/index.d.ts +73 -0
  381. package/dist/esm/timeframe/index.d.ts.map +1 -0
  382. package/dist/esm/timeframe/index.js +131 -0
  383. package/dist/esm/timeframe/index.js.map +1 -0
  384. package/dist/esm/types/index.d.ts +343 -0
  385. package/dist/esm/types/index.d.ts.map +1 -0
  386. package/dist/esm/types/index.js +17 -0
  387. package/dist/esm/types/index.js.map +1 -0
  388. package/dist/esm/types/metadata.d.ts +300 -0
  389. package/dist/esm/types/metadata.d.ts.map +1 -0
  390. package/dist/esm/types/metadata.js +7 -0
  391. package/dist/esm/types/metadata.js.map +1 -0
  392. package/dist/esm/utils/index.d.ts +167 -0
  393. package/dist/esm/utils/index.d.ts.map +1 -0
  394. package/dist/esm/utils/index.js +295 -0
  395. package/dist/esm/utils/index.js.map +1 -0
  396. package/package.json +53 -23
  397. package/src/array/index.ts +1056 -0
  398. package/src/box/index.ts +680 -0
  399. package/src/callsite/index.ts +104 -0
  400. package/src/chartpoint/index.ts +126 -0
  401. package/src/color/index.ts +411 -0
  402. package/src/compare/index.ts +46 -0
  403. package/src/drawing/registry.ts +106 -0
  404. package/src/index.ts +201 -0
  405. package/src/indicator.ts +185 -0
  406. package/src/input.ts +280 -0
  407. package/src/label/index.ts +490 -0
  408. package/src/lib/index.ts +8 -0
  409. package/src/lib/zigzag/index.ts +13 -0
  410. package/src/lib/zigzag/zigzag.ts +318 -0
  411. package/src/line/index.ts +530 -0
  412. package/src/linefill/index.ts +152 -0
  413. package/src/map/index.ts +115 -0
  414. package/src/math/index.ts +1071 -0
  415. package/src/matrix/index.ts +2697 -0
  416. package/src/plot.ts +121 -0
  417. package/src/polyline/index.ts +184 -0
  418. package/src/runtime/adapters/LightweightChartsAdapter.ts +201 -0
  419. package/src/runtime/adapters/SimpleInputAdapter.ts +132 -0
  420. package/src/runtime/index.ts +52 -0
  421. package/src/runtime/inputs.ts +377 -0
  422. package/src/runtime/runtime.ts +241 -0
  423. package/src/runtime/series.ts +644 -0
  424. package/src/runtime/types.ts +292 -0
  425. package/src/script/index.ts +1865 -0
  426. package/src/security/resample.ts +119 -0
  427. package/src/session/bars.ts +262 -0
  428. package/src/session/calendar.ts +199 -0
  429. package/src/str/dateformat.ts +104 -0
  430. package/src/str/index.ts +557 -0
  431. package/src/str/messageformat.ts +109 -0
  432. package/src/str/numberformat.ts +197 -0
  433. package/src/strategy/index.ts +281 -0
  434. package/src/ta/index.ts +3580 -0
  435. package/src/ta/running-sum.ts +117 -0
  436. package/src/ta-series.ts +1036 -0
  437. package/src/text/index.ts +14 -0
  438. package/src/time/datestring.ts +96 -0
  439. package/src/time/index.ts +161 -0
  440. package/src/time/session.ts +79 -0
  441. package/src/time/timezone.ts +180 -0
  442. package/src/timeframe/index.ts +144 -0
  443. package/src/types/index.ts +398 -0
  444. package/src/types/metadata.ts +334 -0
  445. package/src/utils/index.ts +334 -0
  446. package/dist/array/index.d.ts +0 -57
  447. package/dist/array/index.d.ts.map +0 -1
  448. package/dist/box/index.d.ts +0 -37
  449. package/dist/box/index.d.ts.map +0 -1
  450. package/dist/callsite/index.d.ts +0 -7
  451. package/dist/callsite/index.d.ts.map +0 -1
  452. package/dist/chartpoint/index.d.ts +0 -8
  453. package/dist/chartpoint/index.d.ts.map +0 -1
  454. package/dist/color/index.d.ts +0 -28
  455. package/dist/color/index.d.ts.map +0 -1
  456. package/dist/compare/index.d.ts +0 -8
  457. package/dist/compare/index.d.ts.map +0 -1
  458. package/dist/drawing/registry.d.ts +0 -19
  459. package/dist/drawing/registry.d.ts.map +0 -1
  460. package/dist/index.cjs +0 -7979
  461. package/dist/index.d.ts +0 -64
  462. package/dist/index.d.ts.map +0 -1
  463. package/dist/index.mjs +0 -7962
  464. package/dist/indicator.d.ts +0 -42
  465. package/dist/indicator.d.ts.map +0 -1
  466. package/dist/input.d.ts +0 -47
  467. package/dist/input.d.ts.map +0 -1
  468. package/dist/label/index.d.ts +0 -30
  469. package/dist/label/index.d.ts.map +0 -1
  470. package/dist/lib/index.d.ts +0 -2
  471. package/dist/lib/index.d.ts.map +0 -1
  472. package/dist/lib/zigzag/index.d.ts.map +0 -1
  473. package/dist/lib/zigzag/zigzag.d.ts +0 -47
  474. package/dist/lib/zigzag/zigzag.d.ts.map +0 -1
  475. package/dist/line/index.d.ts +0 -30
  476. package/dist/line/index.d.ts.map +0 -1
  477. package/dist/linefill/index.d.ts +0 -10
  478. package/dist/linefill/index.d.ts.map +0 -1
  479. package/dist/map/index.d.ts +0 -14
  480. package/dist/map/index.d.ts.map +0 -1
  481. package/dist/math/index.d.ts +0 -53
  482. package/dist/math/index.d.ts.map +0 -1
  483. package/dist/matrix/index.d.ts +0 -52
  484. package/dist/matrix/index.d.ts.map +0 -1
  485. package/dist/plot.d.ts +0 -20
  486. package/dist/plot.d.ts.map +0 -1
  487. package/dist/polyline/index.d.ts +0 -11
  488. package/dist/polyline/index.d.ts.map +0 -1
  489. package/dist/runtime/adapters/LightweightChartsAdapter.d.ts +0 -15
  490. package/dist/runtime/adapters/LightweightChartsAdapter.d.ts.map +0 -1
  491. package/dist/runtime/adapters/SimpleInputAdapter.d.ts +0 -16
  492. package/dist/runtime/adapters/SimpleInputAdapter.d.ts.map +0 -1
  493. package/dist/runtime/index.cjs +0 -600
  494. package/dist/runtime/index.d.ts.map +0 -1
  495. package/dist/runtime/index.mjs +0 -577
  496. package/dist/runtime/inputs.d.ts +0 -13
  497. package/dist/runtime/inputs.d.ts.map +0 -1
  498. package/dist/runtime/runtime.d.ts +0 -16
  499. package/dist/runtime/runtime.d.ts.map +0 -1
  500. package/dist/runtime/series.d.ts +0 -60
  501. package/dist/runtime/series.d.ts.map +0 -1
  502. package/dist/runtime/types.d.ts +0 -122
  503. package/dist/runtime/types.d.ts.map +0 -1
  504. package/dist/script/index.cjs +0 -6372
  505. package/dist/script/index.d.ts +0 -709
  506. package/dist/script/index.d.ts.map +0 -1
  507. package/dist/script/index.mjs +0 -6355
  508. package/dist/security/resample.d.ts +0 -13
  509. package/dist/security/resample.d.ts.map +0 -1
  510. package/dist/session/bars.d.ts +0 -34
  511. package/dist/session/bars.d.ts.map +0 -1
  512. package/dist/session/calendar.d.ts +0 -31
  513. package/dist/session/calendar.d.ts.map +0 -1
  514. package/dist/str/dateformat.d.ts +0 -2
  515. package/dist/str/dateformat.d.ts.map +0 -1
  516. package/dist/str/index.d.ts +0 -24
  517. package/dist/str/index.d.ts.map +0 -1
  518. package/dist/str/messageformat.d.ts +0 -2
  519. package/dist/str/messageformat.d.ts.map +0 -1
  520. package/dist/str/numberformat.d.ts +0 -3
  521. package/dist/str/numberformat.d.ts.map +0 -1
  522. package/dist/strategy/index.d.ts.map +0 -1
  523. package/dist/ta/index.d.ts +0 -72
  524. package/dist/ta/index.d.ts.map +0 -1
  525. package/dist/ta-series.d.ts +0 -143
  526. package/dist/ta-series.d.ts.map +0 -1
  527. package/dist/text/index.d.ts +0 -4
  528. package/dist/text/index.d.ts.map +0 -1
  529. package/dist/time/datestring.d.ts +0 -2
  530. package/dist/time/datestring.d.ts.map +0 -1
  531. package/dist/time/index.d.ts +0 -15
  532. package/dist/time/index.d.ts.map +0 -1
  533. package/dist/time/session.d.ts +0 -2
  534. package/dist/time/session.d.ts.map +0 -1
  535. package/dist/time/timezone.d.ts +0 -13
  536. package/dist/time/timezone.d.ts.map +0 -1
  537. package/dist/timeframe/index.d.ts +0 -17
  538. package/dist/timeframe/index.d.ts.map +0 -1
  539. package/dist/types/index.d.ts +0 -181
  540. package/dist/types/index.d.ts.map +0 -1
  541. package/dist/types/metadata.d.ts +0 -131
  542. package/dist/types/metadata.d.ts.map +0 -1
  543. package/dist/utils/index.d.ts +0 -26
  544. package/dist/utils/index.d.ts.map +0 -1
@@ -0,0 +1,2697 @@
1
+ /**
2
+ * Matrix namespace
3
+ * Mirrors PineScript's matrix.* functions
4
+ */
5
+
6
+ import type { PineMatrix, PineArray, simple_int, int, bool, float } from '../types/index.js';
7
+
8
+ /**
9
+ * Creates a new matrix
10
+ *
11
+ * @param rows - Number of rows
12
+ * @param columns - Number of columns
13
+ * @param initial_value - Initial value for all elements
14
+ * @returns A new matrix object
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // Create a 2x3 matrix filled with zeros
19
+ * const m = matrix.new_matrix(2, 3, 0);
20
+ *
21
+ * // Create a 3x3 identity-like matrix
22
+ * const m2 = matrix.new_matrix(3, 3, 1);
23
+ * ```
24
+ */
25
+ export function new_matrix<T>(
26
+ rows: simple_int,
27
+ columns: simple_int,
28
+ initial_value?: T
29
+ ): PineMatrix<T> {
30
+ const data: T[][] = [];
31
+ for (let i = 0; i < rows; i++) {
32
+ const row: T[] = [];
33
+ for (let j = 0; j < columns; j++) {
34
+ row.push(initial_value as T);
35
+ }
36
+ data.push(row);
37
+ }
38
+ return { rows, columns, data };
39
+ }
40
+
41
+ /**
42
+ * Get element at position
43
+ *
44
+ * The function returns the element with the specified index of the matrix.
45
+ *
46
+ * @param id - A matrix object
47
+ * @param row - Index of the required row
48
+ * @param column - Index of the required column
49
+ * @returns The value of the element at the row and column index
50
+ *
51
+ * @remarks
52
+ * Indexing of the rows and columns starts at zero.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * // Create a 2x3 matrix with value 5
57
+ * const m = matrix.new_matrix(2, 3, 5);
58
+ *
59
+ * // Get element at row 0, column 0
60
+ * const x = matrix.get(m, 0, 0); // Returns: 5
61
+ * ```
62
+ */
63
+ export function get<T>(id: PineMatrix<T>, row: simple_int, column: simple_int): T {
64
+ if (row < 0 || row >= id.rows || column < 0 || column >= id.columns) {
65
+ throw new Error(`Matrix index out of bounds: [${row}, ${column}] for matrix of size [${id.rows}, ${id.columns}]`);
66
+ }
67
+ return id.data[row]![column]!;
68
+ }
69
+
70
+ /**
71
+ * Set element at position
72
+ *
73
+ * The function assigns value to the element at the row and column of the matrix.
74
+ *
75
+ * @param id - A matrix object
76
+ * @param row - The row index of the element to be modified
77
+ * @param column - The column index of the element to be modified
78
+ * @param value - The new value to be set
79
+ *
80
+ * @remarks
81
+ * Indexing of the rows and columns starts at zero.
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // Create a 2x3 matrix with value 4
86
+ * const m = matrix.new_matrix(2, 3, 4);
87
+ *
88
+ * // Replace value at row 0, column 1 with 3
89
+ * matrix.set(m, 0, 1, 3);
90
+ *
91
+ * // Now m[0][1] === 3
92
+ * ```
93
+ */
94
+ export function set<T>(id: PineMatrix<T>, row: simple_int, column: simple_int, value: T): void {
95
+ if (row < 0 || row >= id.rows || column < 0 || column >= id.columns) {
96
+ throw new Error(`Matrix index out of bounds: [${row}, ${column}] for matrix of size [${id.rows}, ${id.columns}]`);
97
+ }
98
+ id.data[row]![column] = value;
99
+ }
100
+
101
+ /**
102
+ * Get number of rows
103
+ *
104
+ * The function returns the number of rows in the matrix.
105
+ *
106
+ * @param id - A matrix object
107
+ * @returns The number of rows in the matrix
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * // Create a 2x6 matrix
112
+ * const m = matrix.new_matrix(2, 6, 0);
113
+ *
114
+ * // Get the quantity of rows
115
+ * const x = matrix.rows(m); // Returns: 2
116
+ * ```
117
+ */
118
+ export function rows<T>(id: PineMatrix<T>): int {
119
+ return id.rows;
120
+ }
121
+
122
+ /**
123
+ * Get number of columns
124
+ *
125
+ * The function returns the number of columns in the matrix.
126
+ *
127
+ * @param id - A matrix object
128
+ * @returns The number of columns in the matrix
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // Create a 2x6 matrix
133
+ * const m = matrix.new_matrix(2, 6, 0);
134
+ *
135
+ * // Get the quantity of columns
136
+ * const x = matrix.columns(m); // Returns: 6
137
+ * ```
138
+ */
139
+ export function columns<T>(id: PineMatrix<T>): int {
140
+ return id.columns;
141
+ }
142
+
143
+ /**
144
+ * Get total number of elements
145
+ *
146
+ * The function returns the total number of all matrix elements.
147
+ *
148
+ * @param id - A matrix object
149
+ * @returns The total number of elements (rows * columns)
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * // Create a 3x4 matrix
154
+ * const m = matrix.new_matrix(3, 4, 0);
155
+ *
156
+ * // Get total element count
157
+ * const count = matrix.elements_count(m); // Returns: 12
158
+ * ```
159
+ */
160
+ export function elements_count<T>(id: PineMatrix<T>): int {
161
+ return id.rows * id.columns;
162
+ }
163
+
164
+ /**
165
+ * Get row as array
166
+ *
167
+ * The function creates a one-dimensional array from the elements of a matrix row.
168
+ *
169
+ * @param id - A matrix object
170
+ * @param row_index - Index of the required row
171
+ * @returns An array containing the values of the specified row
172
+ *
173
+ * @remarks
174
+ * Indexing of rows starts at 0.
175
+ * Returns a copy of the row data.
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * // Create a 2x3 matrix
180
+ * const m = matrix.new_matrix(2, 3, 5);
181
+ * matrix.set(m, 0, 0, 1);
182
+ * matrix.set(m, 0, 1, 2);
183
+ * matrix.set(m, 0, 2, 3);
184
+ *
185
+ * // Get the first row as an array
186
+ * const a = matrix.row(m, 0); // Returns: [1, 2, 3]
187
+ * ```
188
+ */
189
+ export function row<T>(id: PineMatrix<T>, row_index: simple_int): PineArray<T> {
190
+ if (row_index < 0 || row_index >= id.rows) {
191
+ throw new Error(`Row index out of bounds: ${row_index} for matrix with ${id.rows} rows`);
192
+ }
193
+ return [...id.data[row_index]!] as PineArray<T>;
194
+ }
195
+
196
+ /**
197
+ * Get column as array
198
+ *
199
+ * The function creates a one-dimensional array from the elements of a matrix column.
200
+ *
201
+ * @param id - A matrix object
202
+ * @param column_index - Index of the required column
203
+ * @returns An array containing the values of the specified column
204
+ *
205
+ * @remarks
206
+ * Indexing of columns starts at 0.
207
+ * Returns a copy of the column data.
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * // Create a 3x2 matrix
212
+ * const m = matrix.new_matrix(3, 2, 0);
213
+ * matrix.set(m, 0, 0, 1);
214
+ * matrix.set(m, 1, 0, 2);
215
+ * matrix.set(m, 2, 0, 3);
216
+ *
217
+ * // Get the first column as an array
218
+ * const a = matrix.col(m, 0); // Returns: [1, 2, 3]
219
+ * ```
220
+ */
221
+ export function col<T>(id: PineMatrix<T>, column_index: simple_int): PineArray<T> {
222
+ if (column_index < 0 || column_index >= id.columns) {
223
+ throw new Error(`Column index out of bounds: ${column_index} for matrix with ${id.columns} columns`);
224
+ }
225
+ return id.data.map(r => r[column_index]!) as PineArray<T>;
226
+ }
227
+
228
+ /**
229
+ * Create a deep copy of a matrix
230
+ *
231
+ * The function creates a new matrix which is a copy of the original.
232
+ *
233
+ * @param id - A matrix object to copy
234
+ * @returns A new matrix object that is a deep copy of the original
235
+ *
236
+ * @remarks
237
+ * Unlike a simple assignment operation which would only copy the reference,
238
+ * this function creates an actual copy of the matrix data.
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * // Create a 2x3 matrix with value 1
243
+ * const m1 = matrix.new_matrix(2, 3, 1);
244
+ *
245
+ * // Copy the matrix
246
+ * const m2 = matrix.copy(m1);
247
+ *
248
+ * // Modifying m2 will not affect m1
249
+ * matrix.set(m2, 0, 0, 99);
250
+ * // m1[0][0] is still 1
251
+ * // m2[0][0] is now 99
252
+ * ```
253
+ */
254
+ export function copy<T>(id: PineMatrix<T>): PineMatrix<T> {
255
+ const newData: T[][] = id.data.map(r => [...r]);
256
+ return {
257
+ rows: id.rows,
258
+ columns: id.columns,
259
+ data: newData
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Fill matrix with value
265
+ *
266
+ * The function fills a rectangular area of the matrix defined by the indices
267
+ * from_row to to_row (not including it) and from_column to to_column (not including it)
268
+ * with the specified value.
269
+ *
270
+ * @param id - A matrix object
271
+ * @param value - The value to fill with
272
+ * @param from_row - Row index from which the fill will begin (inclusive). Default: 0
273
+ * @param to_row - Row index where the fill will end (not inclusive). Default: matrix.rows
274
+ * @param from_column - Column index from which the fill will begin (inclusive). Default: 0
275
+ * @param to_column - Column index where the fill will end (not inclusive). Default: matrix.columns
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * // Create a 4x5 matrix with value 0
280
+ * const m = matrix.new_matrix(4, 5, 0);
281
+ *
282
+ * // Fill rows 0-1 and columns 1-2 with value 9
283
+ * matrix.fill(m, 9, 0, 2, 1, 3);
284
+ *
285
+ * // Result: positions [0,1], [0,2], [1,1], [1,2] are now 9
286
+ * ```
287
+ */
288
+ export function fill<T>(
289
+ id: PineMatrix<T>,
290
+ value: T,
291
+ from_row: simple_int = 0,
292
+ to_row?: simple_int,
293
+ from_column: simple_int = 0,
294
+ to_column?: simple_int
295
+ ): void {
296
+ const endRow = to_row ?? id.rows;
297
+ const endCol = to_column ?? id.columns;
298
+
299
+ for (let i = from_row; i < endRow; i++) {
300
+ for (let j = from_column; j < endCol; j++) {
301
+ id.data[i]![j] = value;
302
+ }
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Test if matrix is square
308
+ *
309
+ * The function determines if the matrix is square (it has the same number of rows and columns).
310
+ *
311
+ * @param id - Matrix object to test
312
+ * @returns true if the matrix is square, false otherwise
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * // Create a 3x3 square matrix
317
+ * const m1 = matrix.new_matrix(3, 3, 0);
318
+ * const isSquare1 = matrix.is_square(m1); // Returns: true
319
+ *
320
+ * // Create a 2x3 non-square matrix
321
+ * const m2 = matrix.new_matrix(2, 3, 0);
322
+ * const isSquare2 = matrix.is_square(m2); // Returns: false
323
+ * ```
324
+ */
325
+ export function is_square<T>(id: PineMatrix<T>): bool {
326
+ return id.rows === id.columns;
327
+ }
328
+
329
+ /**
330
+ * Test if matrix is a zero matrix
331
+ *
332
+ * The function determines if all elements of the matrix are zero.
333
+ *
334
+ * @param id - Matrix object to check (int/float)
335
+ * @returns true if all elements are zero, false otherwise
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * // Create a 2x2 zero matrix
340
+ * const m1 = matrix.new_matrix(2, 2, 0);
341
+ * const isZero1 = matrix.is_zero(m1); // Returns: true
342
+ *
343
+ * // Create a matrix with non-zero element
344
+ * const m2 = matrix.new_matrix(2, 2, 0);
345
+ * matrix.set(m2, 0, 0, 1);
346
+ * const isZero2 = matrix.is_zero(m2); // Returns: false
347
+ * ```
348
+ */
349
+ export function is_zero(id: PineMatrix<float>): bool {
350
+ for (let i = 0; i < id.rows; i++) {
351
+ for (let j = 0; j < id.columns; j++) {
352
+ if (id.data[i]![j] !== 0) {
353
+ return false;
354
+ }
355
+ }
356
+ }
357
+ return true;
358
+ }
359
+
360
+ /**
361
+ * Test if matrix is binary
362
+ *
363
+ * The function determines if the matrix is binary (when all elements are 0 or 1).
364
+ *
365
+ * @param id - Matrix object to test (int/float)
366
+ * @returns true if the matrix is binary, false otherwise
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * // Create a binary matrix
371
+ * const m1 = matrix.new_matrix(2, 2, 0);
372
+ * matrix.set(m1, 0, 0, 1);
373
+ * matrix.set(m1, 1, 1, 1);
374
+ * const isBinary1 = matrix.is_binary(m1); // Returns: true
375
+ *
376
+ * // Create a non-binary matrix
377
+ * const m2 = matrix.new_matrix(2, 2, 0);
378
+ * matrix.set(m2, 0, 0, 2);
379
+ * const isBinary2 = matrix.is_binary(m2); // Returns: false
380
+ * ```
381
+ */
382
+ export function is_binary(id: PineMatrix<float>): bool {
383
+ for (let i = 0; i < id.rows; i++) {
384
+ for (let j = 0; j < id.columns; j++) {
385
+ const val = id.data[i]![j];
386
+ if (val !== 0 && val !== 1) {
387
+ return false;
388
+ }
389
+ }
390
+ }
391
+ return true;
392
+ }
393
+
394
+ // ==========================================
395
+ // Row/Column Operations
396
+ // ==========================================
397
+
398
+ /**
399
+ * Add row to matrix
400
+ *
401
+ * Inserts a new row at the specified index of the matrix.
402
+ *
403
+ * @param id - A matrix object
404
+ * @param row - Optional. The index of the new row. Must be a value from 0 to matrix.rows(id).
405
+ * All existing rows with indices >= this value increase their index by one.
406
+ * Default is matrix.rows(id) (append at end).
407
+ * @param array_id - Optional. An array to use as the new row. If the matrix is empty, the array
408
+ * can be of any size. Otherwise, its size must equal matrix.columns(id).
409
+ * By default, inserts a row of undefined values.
410
+ *
411
+ * @remarks
412
+ * Indexing of rows starts at zero.
413
+ * Rather than add rows to an empty matrix, it is far more efficient to declare a matrix
414
+ * with explicit dimensions and fill it with values.
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * // Create a 2x3 matrix with zeros
419
+ * const m = matrix.new_matrix(2, 3, 0);
420
+ *
421
+ * // Add a row at the end with default values
422
+ * matrix.add_row(m);
423
+ *
424
+ * // Add an array as the first row
425
+ * const arr = [1, 2, 3];
426
+ * matrix.add_row(m, 0, arr);
427
+ * ```
428
+ */
429
+ export function add_row<T>(id: PineMatrix<T>, row?: simple_int, array_id?: PineArray<T>): void {
430
+ const insertIndex = row ?? id.rows;
431
+
432
+ if (insertIndex < 0 || insertIndex > id.rows) {
433
+ throw new Error(`Row index out of bounds: ${insertIndex} for matrix with ${id.rows} rows`);
434
+ }
435
+
436
+ let newRow: T[];
437
+
438
+ if (array_id !== undefined) {
439
+ // If matrix is not empty, array size must match columns
440
+ if (id.columns > 0 && array_id.length !== id.columns) {
441
+ throw new Error(`Array size ${array_id.length} does not match matrix columns ${id.columns}`);
442
+ }
443
+ newRow = [...array_id];
444
+ // If matrix was empty, set columns based on array
445
+ if (id.rows === 0 && id.columns === 0) {
446
+ id.columns = array_id.length;
447
+ }
448
+ } else {
449
+ // Create row with undefined values
450
+ newRow = new Array(id.columns).fill(undefined) as T[];
451
+ }
452
+
453
+ // Insert row at specified index
454
+ id.data.splice(insertIndex, 0, newRow);
455
+ id.rows++;
456
+ }
457
+
458
+ /**
459
+ * Add column to matrix
460
+ *
461
+ * Inserts a new column at the specified index of the matrix.
462
+ *
463
+ * @param id - A matrix object
464
+ * @param column - Optional. The index of the new column. Must be a value from 0 to matrix.columns(id).
465
+ * All existing columns with indices >= this value increase their index by one.
466
+ * Default is matrix.columns(id) (append at end).
467
+ * @param array_id - Optional. An array to use as the new column. If the matrix is empty, the array
468
+ * can be of any size. Otherwise, its size must equal matrix.rows(id).
469
+ * By default, inserts a column of undefined values.
470
+ *
471
+ * @remarks
472
+ * Rather than add columns to an empty matrix, it is far more efficient to declare a matrix
473
+ * with explicit dimensions and fill it with values. Adding a column is also much slower
474
+ * than adding a row with matrix.add_row().
475
+ *
476
+ * @example
477
+ * ```typescript
478
+ * // Create a 2x3 matrix with zeros
479
+ * const m = matrix.new_matrix(2, 3, 0);
480
+ *
481
+ * // Add a column at the end with default values
482
+ * matrix.add_col(m);
483
+ *
484
+ * // Add an array as the first column
485
+ * const arr = [1, 2];
486
+ * matrix.add_col(m, 0, arr);
487
+ * ```
488
+ */
489
+ export function add_col<T>(id: PineMatrix<T>, column?: simple_int, array_id?: PineArray<T>): void {
490
+ const insertIndex = column ?? id.columns;
491
+
492
+ if (insertIndex < 0 || insertIndex > id.columns) {
493
+ throw new Error(`Column index out of bounds: ${insertIndex} for matrix with ${id.columns} columns`);
494
+ }
495
+
496
+ if (array_id !== undefined) {
497
+ // If matrix is not empty, array size must match rows
498
+ if (id.rows > 0 && array_id.length !== id.rows) {
499
+ throw new Error(`Array size ${array_id.length} does not match matrix rows ${id.rows}`);
500
+ }
501
+ // If matrix was empty, set rows based on array and create empty rows
502
+ if (id.rows === 0 && id.columns === 0) {
503
+ id.rows = array_id.length;
504
+ for (let i = 0; i < array_id.length; i++) {
505
+ id.data.push([]);
506
+ }
507
+ }
508
+ // Insert value at specified column index for each row
509
+ for (let i = 0; i < id.rows; i++) {
510
+ id.data[i]!.splice(insertIndex, 0, array_id[i]!);
511
+ }
512
+ } else {
513
+ // Insert undefined value at specified column index for each row
514
+ for (let i = 0; i < id.rows; i++) {
515
+ id.data[i]!.splice(insertIndex, 0, undefined as T);
516
+ }
517
+ }
518
+
519
+ id.columns++;
520
+ }
521
+
522
+ /**
523
+ * Remove row from matrix
524
+ *
525
+ * Removes the row at the specified index and returns an array containing the removed row's values.
526
+ *
527
+ * @param id - A matrix object
528
+ * @param row - Optional. The index of the row to be deleted.
529
+ * Default is matrix.rows(id) - 1 (last row).
530
+ * @returns An array containing the elements of the removed row
531
+ *
532
+ * @remarks
533
+ * Indexing of rows starts at zero.
534
+ * It is far more efficient to declare matrices with explicit dimensions than to build them
535
+ * by adding or removing rows.
536
+ *
537
+ * @example
538
+ * ```typescript
539
+ * // Create a 2x2 matrix
540
+ * const m = matrix.new_matrix(2, 2, 1);
541
+ * matrix.set(m, 0, 1, 2);
542
+ * matrix.set(m, 1, 0, 3);
543
+ * matrix.set(m, 1, 1, 4);
544
+ *
545
+ * // Remove the first row
546
+ * const arr = matrix.remove_row(m, 0); // Returns: [1, 2]
547
+ * // Matrix now has 1 row
548
+ * ```
549
+ */
550
+ export function remove_row<T>(id: PineMatrix<T>, row?: simple_int): PineArray<T> {
551
+ const removeIndex = row ?? (id.rows - 1);
552
+
553
+ if (removeIndex < 0 || removeIndex >= id.rows) {
554
+ throw new Error(`Row index out of bounds: ${removeIndex} for matrix with ${id.rows} rows`);
555
+ }
556
+
557
+ const removedRow = id.data.splice(removeIndex, 1)[0]!;
558
+ id.rows--;
559
+
560
+ return removedRow as PineArray<T>;
561
+ }
562
+
563
+ /**
564
+ * Remove column from matrix
565
+ *
566
+ * Removes the column at the specified index and returns an array containing the removed column's values.
567
+ *
568
+ * @param id - A matrix object
569
+ * @param column - Optional. The index of the column to be removed.
570
+ * Default is matrix.columns(id) - 1 (last column).
571
+ * @returns An array containing the elements of the removed column
572
+ *
573
+ * @remarks
574
+ * Indexing of columns starts at zero.
575
+ * It is far more efficient to declare matrices with explicit dimensions than to build them
576
+ * by adding or removing columns. Deleting a column is also much slower than deleting a row
577
+ * with matrix.remove_row().
578
+ *
579
+ * @example
580
+ * ```typescript
581
+ * // Create a 2x2 matrix
582
+ * const m = matrix.new_matrix(2, 2, 1);
583
+ * matrix.set(m, 0, 1, 2);
584
+ * matrix.set(m, 1, 0, 3);
585
+ * matrix.set(m, 1, 1, 4);
586
+ *
587
+ * // Remove the first column
588
+ * const arr = matrix.remove_col(m, 0); // Returns: [1, 3]
589
+ * // Matrix now has 1 column
590
+ * ```
591
+ */
592
+ export function remove_col<T>(id: PineMatrix<T>, column?: simple_int): PineArray<T> {
593
+ const removeIndex = column ?? (id.columns - 1);
594
+
595
+ if (removeIndex < 0 || removeIndex >= id.columns) {
596
+ throw new Error(`Column index out of bounds: ${removeIndex} for matrix with ${id.columns} columns`);
597
+ }
598
+
599
+ const removedCol: T[] = [];
600
+ for (let i = 0; i < id.rows; i++) {
601
+ removedCol.push(id.data[i]!.splice(removeIndex, 1)[0]!);
602
+ }
603
+ id.columns--;
604
+
605
+ return removedCol as PineArray<T>;
606
+ }
607
+
608
+ /**
609
+ * Swap two rows
610
+ *
611
+ * Swaps the rows at the index row1 and row2 in the matrix.
612
+ *
613
+ * @param id - A matrix object
614
+ * @param row1 - Index of the first row to be swapped
615
+ * @param row2 - Index of the second row to be swapped
616
+ *
617
+ * @remarks
618
+ * Indexing of rows starts at zero.
619
+ *
620
+ * @example
621
+ * ```typescript
622
+ * // Create a 3x2 matrix
623
+ * const m = matrix.new_matrix(3, 2, 0);
624
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
625
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
626
+ * matrix.set(m, 2, 0, 5); matrix.set(m, 2, 1, 6);
627
+ *
628
+ * // Swap first and second rows
629
+ * matrix.swap_rows(m, 0, 1);
630
+ * // Now row 0 is [3, 4] and row 1 is [1, 2]
631
+ * ```
632
+ */
633
+ export function swap_rows<T>(id: PineMatrix<T>, row1: simple_int, row2: simple_int): void {
634
+ if (row1 < 0 || row1 >= id.rows) {
635
+ throw new Error(`Row1 index out of bounds: ${row1} for matrix with ${id.rows} rows`);
636
+ }
637
+ if (row2 < 0 || row2 >= id.rows) {
638
+ throw new Error(`Row2 index out of bounds: ${row2} for matrix with ${id.rows} rows`);
639
+ }
640
+
641
+ const temp = id.data[row1]!;
642
+ id.data[row1] = id.data[row2]!;
643
+ id.data[row2] = temp;
644
+ }
645
+
646
+ /**
647
+ * Swap two columns
648
+ *
649
+ * Swaps the columns at the index column1 and column2 in the matrix.
650
+ *
651
+ * @param id - A matrix object
652
+ * @param column1 - Index of the first column to be swapped
653
+ * @param column2 - Index of the second column to be swapped
654
+ *
655
+ * @remarks
656
+ * Indexing of columns starts at zero.
657
+ *
658
+ * @example
659
+ * ```typescript
660
+ * // Create a 2x2 matrix
661
+ * const m = matrix.new_matrix(2, 2, 0);
662
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
663
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
664
+ *
665
+ * // Swap first and second columns
666
+ * matrix.swap_columns(m, 0, 1);
667
+ * // Now column 0 is [2, 4] and column 1 is [1, 3]
668
+ * ```
669
+ */
670
+ export function swap_columns<T>(id: PineMatrix<T>, column1: simple_int, column2: simple_int): void {
671
+ if (column1 < 0 || column1 >= id.columns) {
672
+ throw new Error(`Column1 index out of bounds: ${column1} for matrix with ${id.columns} columns`);
673
+ }
674
+ if (column2 < 0 || column2 >= id.columns) {
675
+ throw new Error(`Column2 index out of bounds: ${column2} for matrix with ${id.columns} columns`);
676
+ }
677
+
678
+ for (let i = 0; i < id.rows; i++) {
679
+ const temp = id.data[i]![column1]!;
680
+ id.data[i]![column1] = id.data[i]![column2]!;
681
+ id.data[i]![column2] = temp;
682
+ }
683
+ }
684
+
685
+ // ==========================================
686
+ // Matrix Transformations
687
+ // ==========================================
688
+
689
+ /**
690
+ * Matrix transpose
691
+ *
692
+ * Creates a new, transposed version of the matrix. This interchanges the row and column
693
+ * index of each element.
694
+ *
695
+ * @param id - A matrix object
696
+ * @returns A new matrix containing the transposed version
697
+ *
698
+ * @example
699
+ * ```typescript
700
+ * // Create a 2x3 matrix
701
+ * const m1 = matrix.new_matrix(2, 3, 0);
702
+ * matrix.set(m1, 0, 0, 1); matrix.set(m1, 0, 1, 2); matrix.set(m1, 0, 2, 3);
703
+ * matrix.set(m1, 1, 0, 4); matrix.set(m1, 1, 1, 5); matrix.set(m1, 1, 2, 6);
704
+ *
705
+ * // Transpose to get a 3x2 matrix
706
+ * const m2 = matrix.transpose(m1);
707
+ * // m2 = [[1, 4], [2, 5], [3, 6]]
708
+ * ```
709
+ */
710
+ export function transpose<T>(id: PineMatrix<T>): PineMatrix<T> {
711
+ const newData: T[][] = [];
712
+ for (let j = 0; j < id.columns; j++) {
713
+ const newRow: T[] = [];
714
+ for (let i = 0; i < id.rows; i++) {
715
+ newRow.push(id.data[i]![j]!);
716
+ }
717
+ newData.push(newRow);
718
+ }
719
+ return {
720
+ rows: id.columns,
721
+ columns: id.rows,
722
+ data: newData
723
+ };
724
+ }
725
+
726
+ /**
727
+ * Concatenate matrices
728
+ *
729
+ * Appends the rows of m2 matrix to m1 matrix (vertical concatenation).
730
+ *
731
+ * @param id1 - Matrix object to concatenate into
732
+ * @param id2 - Matrix object whose rows will be appended to id1
733
+ * @returns Returns the id1 matrix concatenated with the id2 matrix
734
+ *
735
+ * @remarks
736
+ * The number of columns in both matrices must be identical.
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * // Create two 2x4 matrices
741
+ * const m1 = matrix.new_matrix(2, 4, 0);
742
+ * const m2 = matrix.new_matrix(2, 4, 1);
743
+ *
744
+ * // Append m2 to m1
745
+ * matrix.concat(m1, m2);
746
+ * // m1 is now 4x4
747
+ * ```
748
+ */
749
+ export function concat<T>(id1: PineMatrix<T>, id2: PineMatrix<T>): PineMatrix<T> {
750
+ if (id1.columns !== id2.columns) {
751
+ throw new Error(`Column count mismatch: ${id1.columns} vs ${id2.columns}`);
752
+ }
753
+
754
+ // Append all rows from id2 to id1
755
+ for (let i = 0; i < id2.rows; i++) {
756
+ id1.data.push([...id2.data[i]!]);
757
+ }
758
+ id1.rows += id2.rows;
759
+
760
+ return id1;
761
+ }
762
+
763
+ /**
764
+ * Extract submatrix
765
+ *
766
+ * Extracts a submatrix from the matrix within the specified indices.
767
+ *
768
+ * @param id - A matrix object
769
+ * @param from_row - Row index from which extraction begins (inclusive). Default: 0
770
+ * @param to_row - Row index where extraction ends (exclusive). Default: matrix.rows(id)
771
+ * @param from_column - Column index from which extraction begins (inclusive). Default: 0
772
+ * @param to_column - Column index where extraction ends (exclusive). Default: matrix.columns(id)
773
+ * @returns A new matrix object containing the submatrix
774
+ *
775
+ * @remarks
776
+ * Indexing of rows and columns starts at zero.
777
+ *
778
+ * @example
779
+ * ```typescript
780
+ * // Create a 2x3 matrix
781
+ * const m1 = matrix.new_matrix(2, 3, 0);
782
+ * matrix.set(m1, 0, 0, 1); matrix.set(m1, 0, 1, 2); matrix.set(m1, 0, 2, 3);
783
+ * matrix.set(m1, 1, 0, 4); matrix.set(m1, 1, 1, 5); matrix.set(m1, 1, 2, 6);
784
+ *
785
+ * // Extract a 2x2 submatrix (columns 1-2)
786
+ * const m2 = matrix.submatrix(m1, 0, 2, 1, 3);
787
+ * // m2 = [[2, 3], [5, 6]]
788
+ * ```
789
+ */
790
+ export function submatrix<T>(
791
+ id: PineMatrix<T>,
792
+ from_row: simple_int = 0,
793
+ to_row?: simple_int,
794
+ from_column: simple_int = 0,
795
+ to_column?: simple_int
796
+ ): PineMatrix<T> {
797
+ const endRow = to_row ?? id.rows;
798
+ const endCol = to_column ?? id.columns;
799
+
800
+ if (from_row < 0 || from_row > id.rows) {
801
+ throw new Error(`from_row index out of bounds: ${from_row}`);
802
+ }
803
+ if (endRow < 0 || endRow > id.rows) {
804
+ throw new Error(`to_row index out of bounds: ${endRow}`);
805
+ }
806
+ if (from_column < 0 || from_column > id.columns) {
807
+ throw new Error(`from_column index out of bounds: ${from_column}`);
808
+ }
809
+ if (endCol < 0 || endCol > id.columns) {
810
+ throw new Error(`to_column index out of bounds: ${endCol}`);
811
+ }
812
+
813
+ const newRows = endRow - from_row;
814
+ const newCols = endCol - from_column;
815
+ const newData: T[][] = [];
816
+
817
+ for (let i = from_row; i < endRow; i++) {
818
+ const newRow: T[] = [];
819
+ for (let j = from_column; j < endCol; j++) {
820
+ newRow.push(id.data[i]![j]!);
821
+ }
822
+ newData.push(newRow);
823
+ }
824
+
825
+ return {
826
+ rows: newRows,
827
+ columns: newCols,
828
+ data: newData
829
+ };
830
+ }
831
+
832
+ /**
833
+ * Reshape matrix
834
+ *
835
+ * Rebuilds the matrix to new dimensions. The total number of elements must remain the same.
836
+ *
837
+ * @param id - A matrix object
838
+ * @param rows - The number of rows of the reshaped matrix
839
+ * @param columns - The number of columns of the reshaped matrix
840
+ *
841
+ * @remarks
842
+ * The product of rows * columns must equal the current element count.
843
+ * Elements are read row by row and placed in the new shape row by row.
844
+ *
845
+ * @example
846
+ * ```typescript
847
+ * // Create a 2x3 matrix
848
+ * const m = matrix.new_matrix(2, 3, 0);
849
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2); matrix.set(m, 0, 2, 3);
850
+ * matrix.set(m, 1, 0, 4); matrix.set(m, 1, 1, 5); matrix.set(m, 1, 2, 6);
851
+ *
852
+ * // Reshape to 3x2
853
+ * matrix.reshape(m, 3, 2);
854
+ * // m = [[1, 2], [3, 4], [5, 6]]
855
+ * ```
856
+ */
857
+ export function reshape<T>(id: PineMatrix<T>, rows: simple_int, columns: simple_int): void {
858
+ const totalElements = id.rows * id.columns;
859
+ const newTotalElements = rows * columns;
860
+
861
+ if (totalElements !== newTotalElements) {
862
+ throw new Error(`Cannot reshape ${id.rows}x${id.columns} (${totalElements} elements) to ${rows}x${columns} (${newTotalElements} elements)`);
863
+ }
864
+
865
+ // Flatten the matrix
866
+ const flat: T[] = [];
867
+ for (let i = 0; i < id.rows; i++) {
868
+ for (let j = 0; j < id.columns; j++) {
869
+ flat.push(id.data[i]![j]!);
870
+ }
871
+ }
872
+
873
+ // Rebuild with new dimensions
874
+ const newData: T[][] = [];
875
+ let index = 0;
876
+ for (let i = 0; i < rows; i++) {
877
+ const newRow: T[] = [];
878
+ for (let j = 0; j < columns; j++) {
879
+ newRow.push(flat[index++]!);
880
+ }
881
+ newData.push(newRow);
882
+ }
883
+
884
+ id.rows = rows;
885
+ id.columns = columns;
886
+ id.data = newData;
887
+ }
888
+
889
+ /**
890
+ * Reverse matrix
891
+ *
892
+ * Reverses the order of rows and columns in the matrix. The first row and first column
893
+ * become the last, and the last become the first.
894
+ *
895
+ * @param id - A matrix object
896
+ *
897
+ * @remarks
898
+ * This modifies the matrix in place. Both rows and columns are reversed.
899
+ *
900
+ * @example
901
+ * ```typescript
902
+ * // Create a 2x2 matrix
903
+ * const m = matrix.new_matrix(2, 2, 0);
904
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
905
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
906
+ *
907
+ * // Reverse the matrix
908
+ * matrix.reverse(m);
909
+ * // m = [[4, 3], [2, 1]]
910
+ * ```
911
+ */
912
+ export function reverse<T>(id: PineMatrix<T>): void {
913
+ // Reverse the order of rows
914
+ id.data.reverse();
915
+ // Reverse each row (columns)
916
+ for (let i = 0; i < id.rows; i++) {
917
+ id.data[i]!.reverse();
918
+ }
919
+ }
920
+
921
+ /**
922
+ * Sort matrix by column
923
+ *
924
+ * Rearranges the rows in the matrix following the sorted order of values in the specified column.
925
+ *
926
+ * @param id - A matrix object to be sorted
927
+ * @param column - Index of the column whose values determine the new order of rows. Default: 0
928
+ * @param order - The sort order: 'ascending' or 'descending'. Default: 'ascending'
929
+ *
930
+ * @remarks
931
+ * This modifies the matrix in place.
932
+ *
933
+ * @example
934
+ * ```typescript
935
+ * // Create a 2x2 matrix
936
+ * const m = matrix.new_matrix(2, 2, 0);
937
+ * matrix.set(m, 0, 0, 3); matrix.set(m, 0, 1, 4);
938
+ * matrix.set(m, 1, 0, 1); matrix.set(m, 1, 1, 2);
939
+ *
940
+ * // Sort by first column (ascending)
941
+ * matrix.sort(m);
942
+ * // m = [[1, 2], [3, 4]]
943
+ * ```
944
+ */
945
+ export function sort<T extends number | string>(id: PineMatrix<T>, column: simple_int = 0, order: 'ascending' | 'descending' = 'ascending'): void {
946
+ if (column < 0 || column >= id.columns) {
947
+ throw new Error(`Column index out of bounds: ${column} for matrix with ${id.columns} columns`);
948
+ }
949
+
950
+ id.data.sort((a, b) => {
951
+ const valA = a[column]!;
952
+ const valB = b[column]!;
953
+ if (typeof valA === 'number' && typeof valB === 'number') {
954
+ return order === 'ascending' ? valA - valB : valB - valA;
955
+ }
956
+ // String comparison
957
+ if (order === 'ascending') {
958
+ return valA < valB ? -1 : valA > valB ? 1 : 0;
959
+ } else {
960
+ return valB < valA ? -1 : valB > valA ? 1 : 0;
961
+ }
962
+ });
963
+ }
964
+
965
+ // ==========================================
966
+ // Element-wise Arithmetic
967
+ // ==========================================
968
+
969
+ /**
970
+ * Matrix addition (sum)
971
+ *
972
+ * Returns a new matrix resulting from the element-wise sum of two matrices,
973
+ * or of a matrix and a scalar.
974
+ *
975
+ * @param id1 - First matrix object
976
+ * @param id2 - Second matrix object, or scalar value
977
+ * @returns A new matrix containing the sum
978
+ *
979
+ * @remarks
980
+ * When adding two matrices, they must have the same dimensions.
981
+ *
982
+ * @example
983
+ * ```typescript
984
+ * // Sum of two matrices
985
+ * const m1 = matrix.new_matrix(2, 3, 5);
986
+ * const m2 = matrix.new_matrix(2, 3, 4);
987
+ * const m3 = matrix.sum(m1, m2); // All elements are 9
988
+ *
989
+ * // Sum of matrix and scalar
990
+ * const m4 = matrix.new_matrix(2, 3, 4);
991
+ * const m5 = matrix.sum(m4, 1); // All elements are 5
992
+ * ```
993
+ */
994
+ export function sum(id1: PineMatrix<float>, id2: PineMatrix<float> | float): PineMatrix<float> {
995
+ const newData: float[][] = [];
996
+
997
+ if (typeof id2 === 'number') {
998
+ // Add scalar to each element
999
+ for (let i = 0; i < id1.rows; i++) {
1000
+ const newRow: float[] = [];
1001
+ for (let j = 0; j < id1.columns; j++) {
1002
+ newRow.push(id1.data[i]![j]! + id2);
1003
+ }
1004
+ newData.push(newRow);
1005
+ }
1006
+ return {
1007
+ rows: id1.rows,
1008
+ columns: id1.columns,
1009
+ data: newData
1010
+ };
1011
+ } else {
1012
+ // Add two matrices element-wise
1013
+ if (id1.rows !== id2.rows || id1.columns !== id2.columns) {
1014
+ throw new Error(`Matrix dimensions must match: ${id1.rows}x${id1.columns} vs ${id2.rows}x${id2.columns}`);
1015
+ }
1016
+
1017
+ for (let i = 0; i < id1.rows; i++) {
1018
+ const newRow: float[] = [];
1019
+ for (let j = 0; j < id1.columns; j++) {
1020
+ newRow.push(id1.data[i]![j]! + id2.data[i]![j]!);
1021
+ }
1022
+ newData.push(newRow);
1023
+ }
1024
+ return {
1025
+ rows: id1.rows,
1026
+ columns: id1.columns,
1027
+ data: newData
1028
+ };
1029
+ }
1030
+ }
1031
+
1032
+ /**
1033
+ * Matrix subtraction (diff)
1034
+ *
1035
+ * Returns a new matrix resulting from the element-wise subtraction between two matrices,
1036
+ * or of a matrix and a scalar.
1037
+ *
1038
+ * @param id1 - Matrix to subtract from
1039
+ * @param id2 - Matrix object or scalar value to be subtracted
1040
+ * @returns A new matrix containing the difference
1041
+ *
1042
+ * @remarks
1043
+ * When subtracting two matrices, they must have the same dimensions.
1044
+ *
1045
+ * @example
1046
+ * ```typescript
1047
+ * // Difference between two matrices
1048
+ * const m1 = matrix.new_matrix(2, 3, 5);
1049
+ * const m2 = matrix.new_matrix(2, 3, 4);
1050
+ * const m3 = matrix.diff(m1, m2); // All elements are 1
1051
+ *
1052
+ * // Difference between matrix and scalar
1053
+ * const m4 = matrix.new_matrix(2, 3, 4);
1054
+ * const m5 = matrix.diff(m4, 1); // All elements are 3
1055
+ * ```
1056
+ */
1057
+ export function diff(id1: PineMatrix<float>, id2: PineMatrix<float> | float): PineMatrix<float> {
1058
+ const newData: float[][] = [];
1059
+
1060
+ if (typeof id2 === 'number') {
1061
+ // Subtract scalar from each element
1062
+ for (let i = 0; i < id1.rows; i++) {
1063
+ const newRow: float[] = [];
1064
+ for (let j = 0; j < id1.columns; j++) {
1065
+ newRow.push(id1.data[i]![j]! - id2);
1066
+ }
1067
+ newData.push(newRow);
1068
+ }
1069
+ return {
1070
+ rows: id1.rows,
1071
+ columns: id1.columns,
1072
+ data: newData
1073
+ };
1074
+ } else {
1075
+ // Subtract two matrices element-wise
1076
+ if (id1.rows !== id2.rows || id1.columns !== id2.columns) {
1077
+ throw new Error(`Matrix dimensions must match: ${id1.rows}x${id1.columns} vs ${id2.rows}x${id2.columns}`);
1078
+ }
1079
+
1080
+ for (let i = 0; i < id1.rows; i++) {
1081
+ const newRow: float[] = [];
1082
+ for (let j = 0; j < id1.columns; j++) {
1083
+ newRow.push(id1.data[i]![j]! - id2.data[i]![j]!);
1084
+ }
1085
+ newData.push(newRow);
1086
+ }
1087
+ return {
1088
+ rows: id1.rows,
1089
+ columns: id1.columns,
1090
+ data: newData
1091
+ };
1092
+ }
1093
+ }
1094
+
1095
+ // ==========================================
1096
+ // Statistical Functions
1097
+ // ==========================================
1098
+
1099
+ /**
1100
+ * Average of all elements
1101
+ *
1102
+ * Calculates the average of all elements in the matrix.
1103
+ *
1104
+ * @param id - A matrix object
1105
+ * @returns The average value from the matrix
1106
+ *
1107
+ * @example
1108
+ * ```typescript
1109
+ * // Create a 2x2 matrix
1110
+ * const m = matrix.new_matrix(2, 2, 0);
1111
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
1112
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
1113
+ *
1114
+ * const avg = matrix.avg(m); // Returns: 2.5
1115
+ * ```
1116
+ */
1117
+ export function avg(id: PineMatrix<float>): float {
1118
+ if (id.rows === 0 || id.columns === 0) {
1119
+ return NaN;
1120
+ }
1121
+
1122
+ let total = 0;
1123
+ let count = 0;
1124
+ for (let i = 0; i < id.rows; i++) {
1125
+ for (let j = 0; j < id.columns; j++) {
1126
+ const val = id.data[i]![j];
1127
+ if (val !== null && val !== undefined && !isNaN(val)) {
1128
+ total += val;
1129
+ count++;
1130
+ }
1131
+ }
1132
+ }
1133
+
1134
+ return count === 0 ? NaN : total / count;
1135
+ }
1136
+
1137
+ /**
1138
+ * Minimum element
1139
+ *
1140
+ * Returns the smallest value from the matrix elements.
1141
+ *
1142
+ * @param id - A matrix object
1143
+ * @returns The smallest value from the matrix
1144
+ *
1145
+ * @example
1146
+ * ```typescript
1147
+ * // Create a 2x2 matrix
1148
+ * const m = matrix.new_matrix(2, 2, 0);
1149
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
1150
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
1151
+ *
1152
+ * const minVal = matrix.min(m); // Returns: 1
1153
+ * ```
1154
+ */
1155
+ export function min(id: PineMatrix<float>): float {
1156
+ if (id.rows === 0 || id.columns === 0) {
1157
+ return NaN;
1158
+ }
1159
+
1160
+ let minVal = Infinity;
1161
+ for (let i = 0; i < id.rows; i++) {
1162
+ for (let j = 0; j < id.columns; j++) {
1163
+ const val = id.data[i]![j];
1164
+ if (val !== null && val !== undefined && !isNaN(val) && val < minVal) {
1165
+ minVal = val;
1166
+ }
1167
+ }
1168
+ }
1169
+
1170
+ return minVal === Infinity ? NaN : minVal;
1171
+ }
1172
+
1173
+ /**
1174
+ * Maximum element
1175
+ *
1176
+ * Returns the largest value from the matrix elements.
1177
+ *
1178
+ * @param id - A matrix object
1179
+ * @returns The largest value from the matrix
1180
+ *
1181
+ * @example
1182
+ * ```typescript
1183
+ * // Create a 2x2 matrix
1184
+ * const m = matrix.new_matrix(2, 2, 0);
1185
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
1186
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
1187
+ *
1188
+ * const maxVal = matrix.max(m); // Returns: 4
1189
+ * ```
1190
+ */
1191
+ export function max(id: PineMatrix<float>): float {
1192
+ if (id.rows === 0 || id.columns === 0) {
1193
+ return NaN;
1194
+ }
1195
+
1196
+ let maxVal = -Infinity;
1197
+ for (let i = 0; i < id.rows; i++) {
1198
+ for (let j = 0; j < id.columns; j++) {
1199
+ const val = id.data[i]![j];
1200
+ if (val !== null && val !== undefined && !isNaN(val) && val > maxVal) {
1201
+ maxVal = val;
1202
+ }
1203
+ }
1204
+ }
1205
+
1206
+ return maxVal === -Infinity ? NaN : maxVal;
1207
+ }
1208
+
1209
+ /**
1210
+ * Median element
1211
+ *
1212
+ * Calculates the median ("the middle" value) of matrix elements.
1213
+ *
1214
+ * @param id - A matrix object
1215
+ * @returns The median value from the matrix
1216
+ *
1217
+ * @remarks
1218
+ * NA elements of the matrix are not considered when calculating the median.
1219
+ *
1220
+ * @example
1221
+ * ```typescript
1222
+ * // Create a 2x2 matrix
1223
+ * const m = matrix.new_matrix(2, 2, 0);
1224
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
1225
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
1226
+ *
1227
+ * const medianVal = matrix.median(m); // Returns: 2.5
1228
+ * ```
1229
+ */
1230
+ export function median(id: PineMatrix<float>): float {
1231
+ if (id.rows === 0 || id.columns === 0) {
1232
+ return NaN;
1233
+ }
1234
+
1235
+ // Flatten and filter out NaN/null/undefined
1236
+ const values: float[] = [];
1237
+ for (let i = 0; i < id.rows; i++) {
1238
+ for (let j = 0; j < id.columns; j++) {
1239
+ const val = id.data[i]![j];
1240
+ if (val !== null && val !== undefined && !isNaN(val)) {
1241
+ values.push(val);
1242
+ }
1243
+ }
1244
+ }
1245
+
1246
+ if (values.length === 0) {
1247
+ return NaN;
1248
+ }
1249
+
1250
+ values.sort((a, b) => a - b);
1251
+ const mid = Math.floor(values.length / 2);
1252
+
1253
+ if (values.length % 2 === 0) {
1254
+ return (values[mid - 1]! + values[mid]!) / 2;
1255
+ } else {
1256
+ return values[mid]!;
1257
+ }
1258
+ }
1259
+
1260
+ /**
1261
+ * Mode (most frequent element)
1262
+ *
1263
+ * Calculates the mode of the matrix, which is the most frequently occurring value.
1264
+ * When there are multiple values occurring equally frequently, returns the smallest.
1265
+ *
1266
+ * @param id - A matrix object
1267
+ * @returns The most frequently occurring value, or the smallest if tie
1268
+ *
1269
+ * @remarks
1270
+ * NA elements of the matrix are not considered when calculating the mode.
1271
+ *
1272
+ * @example
1273
+ * ```typescript
1274
+ * // Create a 2x2 matrix
1275
+ * const m = matrix.new_matrix(2, 2, 0);
1276
+ * matrix.set(m, 0, 0, 0); matrix.set(m, 0, 1, 0);
1277
+ * matrix.set(m, 1, 0, 1); matrix.set(m, 1, 1, 1);
1278
+ *
1279
+ * const modeVal = matrix.mode(m); // Returns: 0 (tie, so smallest)
1280
+ * ```
1281
+ */
1282
+ export function mode(id: PineMatrix<float>): float {
1283
+ if (id.rows === 0 || id.columns === 0) {
1284
+ return NaN;
1285
+ }
1286
+
1287
+ const frequency = new Map<float, int>();
1288
+ let maxFreq = 0;
1289
+ let modeValue: float = NaN;
1290
+
1291
+ for (let i = 0; i < id.rows; i++) {
1292
+ for (let j = 0; j < id.columns; j++) {
1293
+ const val = id.data[i]![j];
1294
+ if (val !== null && val !== undefined && !isNaN(val)) {
1295
+ const freq = (frequency.get(val) || 0) + 1;
1296
+ frequency.set(val, freq);
1297
+
1298
+ // Update mode if higher frequency, or same frequency but smaller value
1299
+ if (freq > maxFreq || (freq === maxFreq && val < modeValue)) {
1300
+ maxFreq = freq;
1301
+ modeValue = val;
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+
1307
+ return modeValue;
1308
+ }
1309
+
1310
+ /**
1311
+ * Matrix trace
1312
+ *
1313
+ * Calculates the trace of a matrix (the sum of the main diagonal's elements).
1314
+ *
1315
+ * @param id - A matrix object (must be square)
1316
+ * @returns The trace of the matrix
1317
+ *
1318
+ * @remarks
1319
+ * The matrix must be square. Throws an error for non-square matrices.
1320
+ *
1321
+ * @example
1322
+ * ```typescript
1323
+ * // Create a 2x2 matrix
1324
+ * const m = matrix.new_matrix(2, 2, 0);
1325
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2);
1326
+ * matrix.set(m, 1, 0, 3); matrix.set(m, 1, 1, 4);
1327
+ *
1328
+ * const tr = matrix.trace(m); // Returns: 5 (1 + 4)
1329
+ * ```
1330
+ */
1331
+ export function trace(id: PineMatrix<float>): float {
1332
+ if (!is_square(id)) {
1333
+ throw new Error(`Matrix must be square for trace calculation: ${id.rows}x${id.columns}`);
1334
+ }
1335
+
1336
+ if (id.rows === 0) {
1337
+ return 0;
1338
+ }
1339
+
1340
+ let sum = 0;
1341
+ for (let i = 0; i < id.rows; i++) {
1342
+ const val = id.data[i]![i];
1343
+ if (val !== null && val !== undefined && !isNaN(val)) {
1344
+ sum += val;
1345
+ }
1346
+ }
1347
+
1348
+ return sum;
1349
+ }
1350
+
1351
+ // ==========================================
1352
+ // Boolean Checks
1353
+ // ==========================================
1354
+
1355
+ /**
1356
+ * Test if diagonal matrix
1357
+ *
1358
+ * Determines if the matrix is diagonal (all elements outside the main diagonal are zero).
1359
+ *
1360
+ * @param id - Matrix object to test
1361
+ * @returns true if the matrix is diagonal, false otherwise
1362
+ *
1363
+ * @remarks
1364
+ * Returns false with non-square matrices.
1365
+ *
1366
+ * @example
1367
+ * ```typescript
1368
+ * // Create a diagonal matrix
1369
+ * const m = matrix.new_matrix(3, 3, 0);
1370
+ * matrix.set(m, 0, 0, 1);
1371
+ * matrix.set(m, 1, 1, 2);
1372
+ * matrix.set(m, 2, 2, 3);
1373
+ *
1374
+ * const isDiag = matrix.is_diagonal(m); // Returns: true
1375
+ * ```
1376
+ */
1377
+ export function is_diagonal(id: PineMatrix<float>): bool {
1378
+ if (!is_square(id)) {
1379
+ return false;
1380
+ }
1381
+
1382
+ for (let i = 0; i < id.rows; i++) {
1383
+ for (let j = 0; j < id.columns; j++) {
1384
+ if (i !== j && id.data[i]![j] !== 0) {
1385
+ return false;
1386
+ }
1387
+ }
1388
+ }
1389
+
1390
+ return true;
1391
+ }
1392
+
1393
+ /**
1394
+ * Test if identity matrix
1395
+ *
1396
+ * Determines if a matrix is an identity matrix (elements with ones on the main diagonal
1397
+ * and zeros elsewhere).
1398
+ *
1399
+ * @param id - Matrix object to test
1400
+ * @returns true if id is an identity matrix, false otherwise
1401
+ *
1402
+ * @remarks
1403
+ * Returns false with non-square matrices.
1404
+ *
1405
+ * @example
1406
+ * ```typescript
1407
+ * // Create an identity matrix
1408
+ * const m = matrix.new_matrix(3, 3, 0);
1409
+ * matrix.set(m, 0, 0, 1);
1410
+ * matrix.set(m, 1, 1, 1);
1411
+ * matrix.set(m, 2, 2, 1);
1412
+ *
1413
+ * const isIdent = matrix.is_identity(m); // Returns: true
1414
+ * ```
1415
+ */
1416
+ export function is_identity(id: PineMatrix<float>): bool {
1417
+ if (!is_square(id)) {
1418
+ return false;
1419
+ }
1420
+
1421
+ for (let i = 0; i < id.rows; i++) {
1422
+ for (let j = 0; j < id.columns; j++) {
1423
+ const val = id.data[i]![j];
1424
+ if (i === j) {
1425
+ if (val !== 1) {
1426
+ return false;
1427
+ }
1428
+ } else {
1429
+ if (val !== 0) {
1430
+ return false;
1431
+ }
1432
+ }
1433
+ }
1434
+ }
1435
+
1436
+ return true;
1437
+ }
1438
+
1439
+ /**
1440
+ * Test if symmetric matrix
1441
+ *
1442
+ * Determines if a square matrix is symmetric (elements are symmetric with respect
1443
+ * to the main diagonal, i.e., matrix equals its transpose).
1444
+ *
1445
+ * @param id - Matrix object to test
1446
+ * @returns true if the matrix is symmetric, false otherwise
1447
+ *
1448
+ * @remarks
1449
+ * Returns false with non-square matrices.
1450
+ *
1451
+ * @example
1452
+ * ```typescript
1453
+ * // Create a symmetric matrix
1454
+ * const m = matrix.new_matrix(3, 3, 0);
1455
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2); matrix.set(m, 0, 2, 3);
1456
+ * matrix.set(m, 1, 0, 2); matrix.set(m, 1, 1, 4); matrix.set(m, 1, 2, 5);
1457
+ * matrix.set(m, 2, 0, 3); matrix.set(m, 2, 1, 5); matrix.set(m, 2, 2, 6);
1458
+ *
1459
+ * const isSym = matrix.is_symmetric(m); // Returns: true
1460
+ * ```
1461
+ */
1462
+ export function is_symmetric(id: PineMatrix<float>): bool {
1463
+ if (!is_square(id)) {
1464
+ return false;
1465
+ }
1466
+
1467
+ for (let i = 0; i < id.rows; i++) {
1468
+ for (let j = i + 1; j < id.columns; j++) {
1469
+ if (id.data[i]![j] !== id.data[j]![i]) {
1470
+ return false;
1471
+ }
1472
+ }
1473
+ }
1474
+
1475
+ return true;
1476
+ }
1477
+
1478
+ /**
1479
+ * Test if antisymmetric (skew-symmetric) matrix
1480
+ *
1481
+ * Determines if a matrix is antisymmetric (its transpose equals its negative).
1482
+ * A[i][j] = -A[j][i] for all i, j, and diagonal elements must be 0.
1483
+ *
1484
+ * @param id - Matrix object to test
1485
+ * @returns true if the matrix is antisymmetric, false otherwise
1486
+ *
1487
+ * @remarks
1488
+ * Returns false with non-square matrices.
1489
+ *
1490
+ * @example
1491
+ * ```typescript
1492
+ * // Create an antisymmetric matrix
1493
+ * const m = matrix.new_matrix(3, 3, 0);
1494
+ * matrix.set(m, 0, 1, 2); matrix.set(m, 0, 2, -1);
1495
+ * matrix.set(m, 1, 0, -2); matrix.set(m, 1, 2, 3);
1496
+ * matrix.set(m, 2, 0, 1); matrix.set(m, 2, 1, -3);
1497
+ *
1498
+ * const isAntiSym = matrix.is_antisymmetric(m); // Returns: true
1499
+ * ```
1500
+ */
1501
+ export function is_antisymmetric(id: PineMatrix<float>): bool {
1502
+ if (!is_square(id)) {
1503
+ return false;
1504
+ }
1505
+
1506
+ for (let i = 0; i < id.rows; i++) {
1507
+ // Diagonal elements must be 0
1508
+ if (id.data[i]![i] !== 0) {
1509
+ return false;
1510
+ }
1511
+
1512
+ for (let j = i + 1; j < id.columns; j++) {
1513
+ const upperVal = id.data[i]![j]!;
1514
+ const lowerVal = id.data[j]![i]!;
1515
+ if (upperVal !== -lowerVal) {
1516
+ return false;
1517
+ }
1518
+ }
1519
+ }
1520
+
1521
+ return true;
1522
+ }
1523
+
1524
+ /**
1525
+ * Test if triangular matrix
1526
+ *
1527
+ * Determines if the matrix is triangular (if all elements above or below the main
1528
+ * diagonal are zero).
1529
+ *
1530
+ * @param id - Matrix object to test
1531
+ * @returns true if the matrix is triangular (upper or lower), false otherwise
1532
+ *
1533
+ * @remarks
1534
+ * Returns false with non-square matrices.
1535
+ * Returns true if the matrix is either upper triangular or lower triangular.
1536
+ *
1537
+ * @example
1538
+ * ```typescript
1539
+ * // Create an upper triangular matrix
1540
+ * const m = matrix.new_matrix(3, 3, 0);
1541
+ * matrix.set(m, 0, 0, 1); matrix.set(m, 0, 1, 2); matrix.set(m, 0, 2, 3);
1542
+ * matrix.set(m, 1, 1, 4); matrix.set(m, 1, 2, 5);
1543
+ * matrix.set(m, 2, 2, 6);
1544
+ *
1545
+ * const isTri = matrix.is_triangular(m); // Returns: true
1546
+ * ```
1547
+ */
1548
+ export function is_triangular(id: PineMatrix<float>): bool {
1549
+ if (!is_square(id)) {
1550
+ return false;
1551
+ }
1552
+
1553
+ // Check if upper triangular (all elements below diagonal are 0)
1554
+ let isUpper = true;
1555
+ for (let i = 1; i < id.rows && isUpper; i++) {
1556
+ for (let j = 0; j < i && isUpper; j++) {
1557
+ if (id.data[i]![j] !== 0) {
1558
+ isUpper = false;
1559
+ }
1560
+ }
1561
+ }
1562
+
1563
+ if (isUpper) {
1564
+ return true;
1565
+ }
1566
+
1567
+ // Check if lower triangular (all elements above diagonal are 0)
1568
+ let isLower = true;
1569
+ for (let i = 0; i < id.rows - 1 && isLower; i++) {
1570
+ for (let j = i + 1; j < id.columns && isLower; j++) {
1571
+ if (id.data[i]![j] !== 0) {
1572
+ isLower = false;
1573
+ }
1574
+ }
1575
+ }
1576
+
1577
+ return isLower;
1578
+ }
1579
+
1580
+ /**
1581
+ * Test if antidiagonal matrix
1582
+ *
1583
+ * Determines if the matrix is anti-diagonal (all elements outside the secondary
1584
+ * diagonal are zero).
1585
+ *
1586
+ * @param id - Matrix object to test
1587
+ * @returns true if the matrix is anti-diagonal, false otherwise
1588
+ *
1589
+ * @remarks
1590
+ * Returns false with non-square matrices.
1591
+ * The anti-diagonal runs from top-right to bottom-left.
1592
+ *
1593
+ * @example
1594
+ * ```typescript
1595
+ * // Create an antidiagonal matrix
1596
+ * const m = matrix.new_matrix(3, 3, 0);
1597
+ * matrix.set(m, 0, 2, 1);
1598
+ * matrix.set(m, 1, 1, 2);
1599
+ * matrix.set(m, 2, 0, 3);
1600
+ *
1601
+ * const isAntiDiag = matrix.is_antidiagonal(m); // Returns: true
1602
+ * ```
1603
+ */
1604
+ export function is_antidiagonal(id: PineMatrix<float>): bool {
1605
+ if (!is_square(id)) {
1606
+ return false;
1607
+ }
1608
+
1609
+ const n = id.rows;
1610
+ for (let i = 0; i < n; i++) {
1611
+ for (let j = 0; j < n; j++) {
1612
+ // Anti-diagonal position: i + j === n - 1
1613
+ const isAntiDiag = (i + j === n - 1);
1614
+ if (!isAntiDiag && id.data[i]![j] !== 0) {
1615
+ return false;
1616
+ }
1617
+ }
1618
+ }
1619
+
1620
+ return true;
1621
+ }
1622
+
1623
+ /**
1624
+ * Test if stochastic matrix
1625
+ *
1626
+ * Determines if the matrix is stochastic (all elements are non-negative and all
1627
+ * row sums equal 1).
1628
+ *
1629
+ * @param id - Matrix object to test
1630
+ * @returns true if the matrix is stochastic, false otherwise
1631
+ *
1632
+ * @remarks
1633
+ * A right stochastic matrix has rows that sum to 1.
1634
+ *
1635
+ * @example
1636
+ * ```typescript
1637
+ * // Create a stochastic matrix
1638
+ * const m = matrix.new_matrix(2, 2, 0);
1639
+ * matrix.set(m, 0, 0, 0.5); matrix.set(m, 0, 1, 0.5);
1640
+ * matrix.set(m, 1, 0, 0.3); matrix.set(m, 1, 1, 0.7);
1641
+ *
1642
+ * const isStoch = matrix.is_stochastic(m); // Returns: true
1643
+ * ```
1644
+ */
1645
+ export function is_stochastic(id: PineMatrix<float>): bool {
1646
+ if (id.rows === 0 || id.columns === 0) {
1647
+ return false;
1648
+ }
1649
+
1650
+ const tolerance = 1e-10;
1651
+
1652
+ for (let i = 0; i < id.rows; i++) {
1653
+ let rowSum = 0;
1654
+ for (let j = 0; j < id.columns; j++) {
1655
+ const val = id.data[i]![j]!;
1656
+ // All elements must be non-negative
1657
+ if (val < 0) {
1658
+ return false;
1659
+ }
1660
+ rowSum += val;
1661
+ }
1662
+ // Row sum must equal 1 (with tolerance for floating point errors)
1663
+ if (Math.abs(rowSum - 1) > tolerance) {
1664
+ return false;
1665
+ }
1666
+ }
1667
+
1668
+ return true;
1669
+ }
1670
+
1671
+ // ==========================================
1672
+ // Linear Algebra Functions (Phase 3)
1673
+ // ==========================================
1674
+
1675
+ /**
1676
+ * Epsilon for floating-point comparisons
1677
+ */
1678
+ const EPSILON = 1e-10;
1679
+
1680
+ /**
1681
+ * Helper: Create identity matrix of given size
1682
+ */
1683
+ function createIdentity(n: simple_int): PineMatrix<float> {
1684
+ const m = new_matrix<float>(n, n, 0);
1685
+ for (let i = 0; i < n; i++) {
1686
+ m.data[i]![i] = 1;
1687
+ }
1688
+ return m;
1689
+ }
1690
+
1691
+ /**
1692
+ * Matrix multiplication
1693
+ *
1694
+ * Returns a new matrix resulting from the product between two matrices,
1695
+ * or between a matrix and a scalar, or between a matrix and a vector (array).
1696
+ *
1697
+ * @param id1 - First matrix object
1698
+ * @param id2 - Second matrix object, scalar value, or array (vector)
1699
+ * @returns A new matrix containing the product, or array for matrix × vector
1700
+ *
1701
+ * @remarks
1702
+ * For matrix × matrix: id1's columns must equal id2's rows.
1703
+ * For matrix × vector: the array length must equal id1's columns.
1704
+ * Time complexity: O(n³) for n×n matrices.
1705
+ *
1706
+ * @example
1707
+ * ```typescript
1708
+ * // Product of two matrices
1709
+ * const m1 = matrix.new_matrix(6, 2, 5);
1710
+ * const m2 = matrix.new_matrix(2, 3, 4);
1711
+ * const m3 = matrix.mult(m1, m2); // 6x3 matrix with values 40
1712
+ *
1713
+ * // Product of matrix and scalar
1714
+ * const m4 = matrix.new_matrix(2, 3, 4);
1715
+ * const m5 = matrix.mult(m4, 5); // All elements are 20
1716
+ *
1717
+ * // Product of matrix and vector
1718
+ * const m6 = matrix.new_matrix(2, 3, 4);
1719
+ * const arr = [1, 1, 1];
1720
+ * const result = matrix.mult(m6, arr); // [12, 12]
1721
+ * ```
1722
+ */
1723
+ export function mult(id1: PineMatrix<float>, id2: PineMatrix<float> | float | PineArray<float>): PineMatrix<float> | PineArray<float> {
1724
+ // Matrix × Scalar
1725
+ if (typeof id2 === 'number') {
1726
+ const newData: float[][] = [];
1727
+ for (let i = 0; i < id1.rows; i++) {
1728
+ const newRow: float[] = [];
1729
+ for (let j = 0; j < id1.columns; j++) {
1730
+ newRow.push(id1.data[i]![j]! * id2);
1731
+ }
1732
+ newData.push(newRow);
1733
+ }
1734
+ return {
1735
+ rows: id1.rows,
1736
+ columns: id1.columns,
1737
+ data: newData
1738
+ };
1739
+ }
1740
+
1741
+ // Matrix × Vector (array)
1742
+ if (Array.isArray(id2) && !('rows' in id2)) {
1743
+ const vec = id2 as float[];
1744
+ if (vec.length !== id1.columns) {
1745
+ throw new Error(`Vector length ${vec.length} must equal matrix columns ${id1.columns}`);
1746
+ }
1747
+ const result: float[] = [];
1748
+ for (let i = 0; i < id1.rows; i++) {
1749
+ let sum = 0;
1750
+ for (let j = 0; j < id1.columns; j++) {
1751
+ sum += id1.data[i]![j]! * vec[j]!;
1752
+ }
1753
+ result.push(sum);
1754
+ }
1755
+ return result as PineArray<float>;
1756
+ }
1757
+
1758
+ // Matrix × Matrix
1759
+ const m2 = id2 as PineMatrix<float>;
1760
+ if (id1.columns !== m2.rows) {
1761
+ throw new Error(`Matrix multiplication dimension mismatch: ${id1.rows}x${id1.columns} × ${m2.rows}x${m2.columns}. First matrix columns (${id1.columns}) must equal second matrix rows (${m2.rows})`);
1762
+ }
1763
+
1764
+ const newRows = id1.rows;
1765
+ const newCols = m2.columns;
1766
+ const newData: float[][] = [];
1767
+
1768
+ for (let i = 0; i < newRows; i++) {
1769
+ const newRow: float[] = [];
1770
+ for (let j = 0; j < newCols; j++) {
1771
+ let sum = 0;
1772
+ for (let k = 0; k < id1.columns; k++) {
1773
+ sum += id1.data[i]![k]! * m2.data[k]![j]!;
1774
+ }
1775
+ newRow.push(sum);
1776
+ }
1777
+ newData.push(newRow);
1778
+ }
1779
+
1780
+ return {
1781
+ rows: newRows,
1782
+ columns: newCols,
1783
+ data: newData
1784
+ };
1785
+ }
1786
+
1787
+ /**
1788
+ * Matrix power
1789
+ *
1790
+ * Calculates the product of the matrix by itself 'power' times.
1791
+ * Uses repeated squaring for efficiency: O(n³ log p) for n×n matrix and power p.
1792
+ *
1793
+ * @param id - A matrix object (must be square)
1794
+ * @param power - The number of times the matrix will be multiplied by itself
1795
+ * @returns A new matrix that is id raised to the specified power
1796
+ *
1797
+ * @remarks
1798
+ * The matrix must be square.
1799
+ * power=0 returns the identity matrix.
1800
+ * Negative powers compute the inverse first, then raise to the positive power.
1801
+ *
1802
+ * @example
1803
+ * ```typescript
1804
+ * // Create a 2x2 matrix
1805
+ * const m1 = matrix.new_matrix(2, 2, 2);
1806
+ * // Calculate the power of three
1807
+ * const m2 = matrix.pow(m1, 3);
1808
+ * // m2 = m1 × m1 × m1
1809
+ * ```
1810
+ */
1811
+ export function pow(id: PineMatrix<float>, power: int): PineMatrix<float> {
1812
+ if (!is_square(id)) {
1813
+ throw new Error(`Matrix must be square for power calculation: ${id.rows}x${id.columns}`);
1814
+ }
1815
+
1816
+ const n = id.rows;
1817
+
1818
+ // Handle power = 0: return identity matrix
1819
+ if (power === 0) {
1820
+ return createIdentity(n);
1821
+ }
1822
+
1823
+ // Handle negative powers: compute inverse then raise to positive power
1824
+ let base: PineMatrix<float>;
1825
+ let p = power;
1826
+ if (power < 0) {
1827
+ const inverse = inv(id);
1828
+ if (inverse === null) {
1829
+ throw new Error('Cannot compute negative power of singular matrix');
1830
+ }
1831
+ base = inverse;
1832
+ p = -power;
1833
+ } else {
1834
+ base = copy(id);
1835
+ }
1836
+
1837
+ // Repeated squaring algorithm
1838
+ let result = createIdentity(n);
1839
+
1840
+ while (p > 0) {
1841
+ if (p % 2 === 1) {
1842
+ result = mult(result, base) as PineMatrix<float>;
1843
+ }
1844
+ base = mult(base, base) as PineMatrix<float>;
1845
+ p = Math.floor(p / 2);
1846
+ }
1847
+
1848
+ return result;
1849
+ }
1850
+
1851
+ /**
1852
+ * Matrix determinant
1853
+ *
1854
+ * Computes the determinant of a square matrix using LU decomposition
1855
+ * with partial pivoting.
1856
+ *
1857
+ * @param id - A matrix object (must be square)
1858
+ * @returns The determinant value
1859
+ *
1860
+ * @remarks
1861
+ * Function calculation based on the LU decomposition algorithm.
1862
+ * Time complexity: O(n³)
1863
+ *
1864
+ * @example
1865
+ * ```typescript
1866
+ * // Create a 2x2 matrix
1867
+ * const m = matrix.new_matrix(2, 2, NaN);
1868
+ * matrix.set(m, 0, 0, 3);
1869
+ * matrix.set(m, 0, 1, 7);
1870
+ * matrix.set(m, 1, 0, 1);
1871
+ * matrix.set(m, 1, 1, -4);
1872
+ *
1873
+ * const d = matrix.det(m); // Returns: -19
1874
+ * ```
1875
+ */
1876
+ export function det(id: PineMatrix<float>): float {
1877
+ if (!is_square(id)) {
1878
+ throw new Error(`Matrix must be square for determinant calculation: ${id.rows}x${id.columns}`);
1879
+ }
1880
+
1881
+ const n = id.rows;
1882
+
1883
+ if (n === 0) {
1884
+ return 1; // Empty matrix has determinant 1 by convention
1885
+ }
1886
+
1887
+ if (n === 1) {
1888
+ return id.data[0]![0]!;
1889
+ }
1890
+
1891
+ if (n === 2) {
1892
+ return id.data[0]![0]! * id.data[1]![1]! - id.data[0]![1]! * id.data[1]![0]!;
1893
+ }
1894
+
1895
+ // LU decomposition with partial pivoting
1896
+ // Make a copy to work with
1897
+ const a: float[][] = id.data.map(row => [...row]);
1898
+ let determinant = 1;
1899
+ let swapCount = 0;
1900
+
1901
+ for (let col = 0; col < n; col++) {
1902
+ // Find pivot (partial pivoting)
1903
+ let maxRow = col;
1904
+ let maxVal = Math.abs(a[col]![col]!);
1905
+ for (let row = col + 1; row < n; row++) {
1906
+ const absVal = Math.abs(a[row]![col]!);
1907
+ if (absVal > maxVal) {
1908
+ maxVal = absVal;
1909
+ maxRow = row;
1910
+ }
1911
+ }
1912
+
1913
+ // Swap rows if needed
1914
+ if (maxRow !== col) {
1915
+ const temp = a[col]!;
1916
+ a[col] = a[maxRow]!;
1917
+ a[maxRow] = temp;
1918
+ swapCount++;
1919
+ }
1920
+
1921
+ // If pivot is zero, determinant is zero
1922
+ const pivot = a[col]![col]!;
1923
+ if (Math.abs(pivot) < EPSILON) {
1924
+ return 0;
1925
+ }
1926
+
1927
+ determinant *= pivot;
1928
+
1929
+ // Eliminate below pivot
1930
+ for (let row = col + 1; row < n; row++) {
1931
+ const factor = a[row]![col]! / pivot;
1932
+ for (let j = col; j < n; j++) {
1933
+ a[row]![j] = a[row]![j]! - factor * a[col]![j]!;
1934
+ }
1935
+ }
1936
+ }
1937
+
1938
+ // Adjust sign based on row swaps
1939
+ if (swapCount % 2 === 1) {
1940
+ determinant = -determinant;
1941
+ }
1942
+
1943
+ return determinant;
1944
+ }
1945
+
1946
+ /**
1947
+ * Matrix inverse
1948
+ *
1949
+ * Computes the inverse of a square matrix using Gauss-Jordan elimination
1950
+ * with partial pivoting.
1951
+ *
1952
+ * @param id - A matrix object (must be square and non-singular)
1953
+ * @returns A new matrix that is the inverse, or null if singular
1954
+ *
1955
+ * @remarks
1956
+ * Function calculation based on the LU decomposition algorithm.
1957
+ * Returns null for singular matrices (det = 0).
1958
+ * Time complexity: O(n³)
1959
+ *
1960
+ * @example
1961
+ * ```typescript
1962
+ * // Create a 2x2 matrix
1963
+ * const m1 = matrix.new_matrix(2, 2, NaN);
1964
+ * matrix.set(m1, 0, 0, 1);
1965
+ * matrix.set(m1, 0, 1, 2);
1966
+ * matrix.set(m1, 1, 0, 3);
1967
+ * matrix.set(m1, 1, 1, 4);
1968
+ *
1969
+ * const m2 = matrix.inv(m1);
1970
+ * // m2 = [[-2, 1], [1.5, -0.5]]
1971
+ * ```
1972
+ */
1973
+ export function inv(id: PineMatrix<float>): PineMatrix<float> | null {
1974
+ if (!is_square(id)) {
1975
+ throw new Error(`Matrix must be square for inverse calculation: ${id.rows}x${id.columns}`);
1976
+ }
1977
+
1978
+ const n = id.rows;
1979
+
1980
+ if (n === 0) {
1981
+ return new_matrix<float>(0, 0, 0);
1982
+ }
1983
+
1984
+ // Create augmented matrix [A | I]
1985
+ const aug: float[][] = [];
1986
+ for (let i = 0; i < n; i++) {
1987
+ const row: float[] = [];
1988
+ for (let j = 0; j < n; j++) {
1989
+ row.push(id.data[i]![j]!);
1990
+ }
1991
+ for (let j = 0; j < n; j++) {
1992
+ row.push(i === j ? 1 : 0);
1993
+ }
1994
+ aug.push(row);
1995
+ }
1996
+
1997
+ // Gauss-Jordan elimination with partial pivoting
1998
+ for (let col = 0; col < n; col++) {
1999
+ // Find pivot
2000
+ let maxRow = col;
2001
+ let maxVal = Math.abs(aug[col]![col]!);
2002
+ for (let row = col + 1; row < n; row++) {
2003
+ const absVal = Math.abs(aug[row]![col]!);
2004
+ if (absVal > maxVal) {
2005
+ maxVal = absVal;
2006
+ maxRow = row;
2007
+ }
2008
+ }
2009
+
2010
+ // Swap rows if needed
2011
+ if (maxRow !== col) {
2012
+ const temp = aug[col]!;
2013
+ aug[col] = aug[maxRow]!;
2014
+ aug[maxRow] = temp;
2015
+ }
2016
+
2017
+ // Check for singular matrix
2018
+ const pivot = aug[col]![col]!;
2019
+ if (Math.abs(pivot) < EPSILON) {
2020
+ return null; // Singular matrix
2021
+ }
2022
+
2023
+ // Scale pivot row
2024
+ for (let j = 0; j < 2 * n; j++) {
2025
+ aug[col]![j] = aug[col]![j]! / pivot;
2026
+ }
2027
+
2028
+ // Eliminate column in all other rows
2029
+ for (let row = 0; row < n; row++) {
2030
+ if (row !== col) {
2031
+ const factor = aug[row]![col]!;
2032
+ for (let j = 0; j < 2 * n; j++) {
2033
+ aug[row]![j] = aug[row]![j]! - factor * aug[col]![j]!;
2034
+ }
2035
+ }
2036
+ }
2037
+ }
2038
+
2039
+ // Extract inverse from augmented matrix
2040
+ const inverse: float[][] = [];
2041
+ for (let i = 0; i < n; i++) {
2042
+ const row: float[] = [];
2043
+ for (let j = 0; j < n; j++) {
2044
+ row.push(aug[i]![n + j]!);
2045
+ }
2046
+ inverse.push(row);
2047
+ }
2048
+
2049
+ return {
2050
+ rows: n,
2051
+ columns: n,
2052
+ data: inverse
2053
+ };
2054
+ }
2055
+
2056
+ /**
2057
+ * Matrix pseudo-inverse (Moore-Penrose)
2058
+ *
2059
+ * Computes the pseudo-inverse of a matrix. For non-singular square matrices,
2060
+ * this returns the same result as inv().
2061
+ *
2062
+ * @param id - A matrix object (can be any shape)
2063
+ * @returns A new matrix containing the pseudo-inverse
2064
+ *
2065
+ * @remarks
2066
+ * Uses the formula: A⁺ = (AᵀA)⁻¹Aᵀ for full column rank matrices,
2067
+ * or Aᵀ(AAᵀ)⁻¹ for full row rank matrices.
2068
+ * For singular matrices, uses iterative refinement approach.
2069
+ *
2070
+ * @example
2071
+ * ```typescript
2072
+ * // Create a 2x2 matrix
2073
+ * const m1 = matrix.new_matrix(2, 2, NaN);
2074
+ * matrix.set(m1, 0, 0, 1);
2075
+ * matrix.set(m1, 0, 1, 2);
2076
+ * matrix.set(m1, 1, 0, 3);
2077
+ * matrix.set(m1, 1, 1, 4);
2078
+ *
2079
+ * const m2 = matrix.pinv(m1);
2080
+ * ```
2081
+ */
2082
+ export function pinv(id: PineMatrix<float>): PineMatrix<float> {
2083
+ const m = id.rows;
2084
+ const n = id.columns;
2085
+
2086
+ if (m === 0 || n === 0) {
2087
+ return new_matrix<float>(n, m, 0);
2088
+ }
2089
+
2090
+ // For square non-singular matrices, use regular inverse
2091
+ if (m === n) {
2092
+ const inverse = inv(id);
2093
+ if (inverse !== null) {
2094
+ return inverse;
2095
+ }
2096
+ }
2097
+
2098
+ const At = transpose(id);
2099
+
2100
+ // If matrix has more rows than columns (m >= n), use (AᵀA)⁻¹Aᵀ
2101
+ if (m >= n) {
2102
+ const AtA = mult(At, id) as PineMatrix<float>;
2103
+ const AtA_inv = inv(AtA);
2104
+ if (AtA_inv !== null) {
2105
+ return mult(AtA_inv, At) as PineMatrix<float>;
2106
+ }
2107
+ }
2108
+
2109
+ // If matrix has more columns than rows (n > m), use Aᵀ(AAᵀ)⁻¹
2110
+ const AAt = mult(id, At) as PineMatrix<float>;
2111
+ const AAt_inv = inv(AAt);
2112
+ if (AAt_inv !== null) {
2113
+ return mult(At, AAt_inv) as PineMatrix<float>;
2114
+ }
2115
+
2116
+ // Fallback: Use regularization for rank-deficient matrices
2117
+ // Add small regularization term: (AᵀA + λI)⁻¹Aᵀ
2118
+ const lambda = 1e-10;
2119
+ const AtA = mult(At, id) as PineMatrix<float>;
2120
+
2121
+ // Add regularization
2122
+ for (let i = 0; i < AtA.rows; i++) {
2123
+ AtA.data[i]![i] = AtA.data[i]![i]! + lambda;
2124
+ }
2125
+
2126
+ const AtA_inv = inv(AtA);
2127
+ if (AtA_inv !== null) {
2128
+ return mult(AtA_inv, At) as PineMatrix<float>;
2129
+ }
2130
+
2131
+ // If all else fails, return zero matrix of appropriate dimensions
2132
+ return new_matrix<float>(n, m, 0);
2133
+ }
2134
+
2135
+ /**
2136
+ * Matrix rank
2137
+ *
2138
+ * Calculates the rank of a matrix (number of linearly independent rows/columns)
2139
+ * using Gaussian elimination to row echelon form.
2140
+ *
2141
+ * @param id - A matrix object
2142
+ * @returns The rank of the matrix
2143
+ *
2144
+ * @remarks
2145
+ * Uses row reduction with partial pivoting.
2146
+ * Time complexity: O(n³)
2147
+ *
2148
+ * @example
2149
+ * ```typescript
2150
+ * // Create a 2x2 matrix
2151
+ * const m1 = matrix.new_matrix(2, 2, NaN);
2152
+ * matrix.set(m1, 0, 0, 1);
2153
+ * matrix.set(m1, 0, 1, 2);
2154
+ * matrix.set(m1, 1, 0, 3);
2155
+ * matrix.set(m1, 1, 1, 4);
2156
+ *
2157
+ * const r = matrix.rank(m1); // Returns: 2
2158
+ * ```
2159
+ */
2160
+ export function rank(id: PineMatrix<float>): int {
2161
+ if (id.rows === 0 || id.columns === 0) {
2162
+ return 0;
2163
+ }
2164
+
2165
+ // Make a copy to work with
2166
+ const a: float[][] = id.data.map(row => [...row]);
2167
+ const m = id.rows;
2168
+ const n = id.columns;
2169
+
2170
+ let r = 0; // Current rank (and current pivot row)
2171
+
2172
+ for (let col = 0; col < n && r < m; col++) {
2173
+ // Find pivot
2174
+ let maxRow = r;
2175
+ let maxVal = Math.abs(a[r]![col]!);
2176
+ for (let row = r + 1; row < m; row++) {
2177
+ const absVal = Math.abs(a[row]![col]!);
2178
+ if (absVal > maxVal) {
2179
+ maxVal = absVal;
2180
+ maxRow = row;
2181
+ }
2182
+ }
2183
+
2184
+ // Skip column if all values below are effectively zero
2185
+ if (maxVal < EPSILON) {
2186
+ continue;
2187
+ }
2188
+
2189
+ // Swap rows if needed
2190
+ if (maxRow !== r) {
2191
+ const temp = a[r]!;
2192
+ a[r] = a[maxRow]!;
2193
+ a[maxRow] = temp;
2194
+ }
2195
+
2196
+ // Eliminate below pivot
2197
+ const pivot = a[r]![col]!;
2198
+ for (let row = r + 1; row < m; row++) {
2199
+ const factor = a[row]![col]! / pivot;
2200
+ for (let j = col; j < n; j++) {
2201
+ a[row]![j] = a[row]![j]! - factor * a[r]![j]!;
2202
+ }
2203
+ }
2204
+
2205
+ r++;
2206
+ }
2207
+
2208
+ return r;
2209
+ }
2210
+
2211
+ /**
2212
+ * Matrix eigenvalues
2213
+ *
2214
+ * Computes the eigenvalues of a square matrix using the QR algorithm.
2215
+ *
2216
+ * @param id - A matrix object (must be square)
2217
+ * @returns An array containing the eigenvalues
2218
+ *
2219
+ * @remarks
2220
+ * Uses the Implicit QL Algorithm with shifts.
2221
+ * For non-symmetric matrices, only real eigenvalues are returned accurately.
2222
+ * Complex eigenvalues return their real part for 2x2 matrices.
2223
+ * Time complexity: O(n³) per iteration, typically converges in O(n) iterations.
2224
+ *
2225
+ * @example
2226
+ * ```typescript
2227
+ * // Create a 2x2 matrix
2228
+ * const m1 = matrix.new_matrix(2, 2, NaN);
2229
+ * matrix.set(m1, 0, 0, 2);
2230
+ * matrix.set(m1, 0, 1, 4);
2231
+ * matrix.set(m1, 1, 0, 6);
2232
+ * matrix.set(m1, 1, 1, 8);
2233
+ *
2234
+ * const ev = matrix.eigenvalues(m1); // Returns eigenvalues
2235
+ * ```
2236
+ */
2237
+ export function eigenvalues(id: PineMatrix<float>): PineArray<float> {
2238
+ if (!is_square(id)) {
2239
+ throw new Error(`Matrix must be square for eigenvalue calculation: ${id.rows}x${id.columns}`);
2240
+ }
2241
+
2242
+ const n = id.rows;
2243
+
2244
+ if (n === 0) {
2245
+ return [] as PineArray<float>;
2246
+ }
2247
+
2248
+ if (n === 1) {
2249
+ return [id.data[0]![0]!] as PineArray<float>;
2250
+ }
2251
+
2252
+ // For 2x2 matrices, use quadratic formula
2253
+ if (n === 2) {
2254
+ const a = id.data[0]![0]!;
2255
+ const b = id.data[0]![1]!;
2256
+ const c = id.data[1]![0]!;
2257
+ const d = id.data[1]![1]!;
2258
+
2259
+ // Characteristic polynomial: λ² - (a+d)λ + (ad-bc) = 0
2260
+ const trace = a + d;
2261
+ const determinant = a * d - b * c;
2262
+ const discriminant = trace * trace - 4 * determinant;
2263
+
2264
+ if (discriminant >= 0) {
2265
+ const sqrtDisc = Math.sqrt(discriminant);
2266
+ return [(trace + sqrtDisc) / 2, (trace - sqrtDisc) / 2] as PineArray<float>;
2267
+ } else {
2268
+ // Complex eigenvalues - return real parts
2269
+ return [trace / 2, trace / 2] as PineArray<float>;
2270
+ }
2271
+ }
2272
+
2273
+ // For larger matrices, use QR algorithm
2274
+ // First, reduce to Hessenberg form (more efficient for QR)
2275
+ const h = toHessenberg(id);
2276
+ const result = qrAlgorithm(h, 100); // Max 100 iterations
2277
+
2278
+ return result as PineArray<float>;
2279
+ }
2280
+
2281
+ /**
2282
+ * Helper: Convert matrix to upper Hessenberg form
2283
+ */
2284
+ function toHessenberg(m: PineMatrix<float>): PineMatrix<float> {
2285
+ const n = m.rows;
2286
+ const h: float[][] = m.data.map(row => [...row]);
2287
+
2288
+ for (let k = 0; k < n - 2; k++) {
2289
+ // Find the largest element in column k below diagonal
2290
+ let maxVal = 0;
2291
+ for (let i = k + 1; i < n; i++) {
2292
+ maxVal = Math.max(maxVal, Math.abs(h[i]![k]!));
2293
+ }
2294
+
2295
+ if (maxVal < EPSILON) continue;
2296
+
2297
+ // Compute Householder vector
2298
+ let sigma = 0;
2299
+ for (let i = k + 1; i < n; i++) {
2300
+ sigma += h[i]![k]! * h[i]![k]!;
2301
+ }
2302
+ sigma = Math.sqrt(sigma);
2303
+
2304
+ if (h[k + 1]![k]! < 0) sigma = -sigma;
2305
+
2306
+ const u: float[] = new Array(n).fill(0);
2307
+ u[k + 1] = h[k + 1]![k]! + sigma;
2308
+ for (let i = k + 2; i < n; i++) {
2309
+ u[i] = h[i]![k]!;
2310
+ }
2311
+
2312
+ let uTu = 0;
2313
+ for (let i = k + 1; i < n; i++) {
2314
+ uTu += u[i]! * u[i]!;
2315
+ }
2316
+
2317
+ if (uTu < EPSILON) continue;
2318
+
2319
+ // Apply H = I - 2*u*u'/u'u from left and right
2320
+ // H * A
2321
+ for (let j = k; j < n; j++) {
2322
+ let dot = 0;
2323
+ for (let i = k + 1; i < n; i++) {
2324
+ dot += u[i]! * h[i]![j]!;
2325
+ }
2326
+ const factor = 2 * dot / uTu;
2327
+ for (let i = k + 1; i < n; i++) {
2328
+ h[i]![j] = h[i]![j]! - factor * u[i]!;
2329
+ }
2330
+ }
2331
+
2332
+ // A * H
2333
+ for (let i = 0; i < n; i++) {
2334
+ let dot = 0;
2335
+ for (let j = k + 1; j < n; j++) {
2336
+ dot += h[i]![j]! * u[j]!;
2337
+ }
2338
+ const factor = 2 * dot / uTu;
2339
+ for (let j = k + 1; j < n; j++) {
2340
+ h[i]![j] = h[i]![j]! - factor * u[j]!;
2341
+ }
2342
+ }
2343
+ }
2344
+
2345
+ return { rows: n, columns: n, data: h };
2346
+ }
2347
+
2348
+ /**
2349
+ * Helper: QR algorithm for eigenvalues
2350
+ */
2351
+ function qrAlgorithm(h: PineMatrix<float>, maxIter: int): float[] {
2352
+ const n = h.rows;
2353
+ const a: float[][] = h.data.map(row => [...row]);
2354
+ const eigenvals: float[] = [];
2355
+
2356
+ let remaining = n;
2357
+
2358
+ for (let iter = 0; iter < maxIter && remaining > 1; iter++) {
2359
+ // Check for convergence (subdiagonal element near zero)
2360
+ let converged = false;
2361
+ for (let i = remaining - 1; i >= 1; i--) {
2362
+ if (Math.abs(a[i]![i - 1]!) < EPSILON * (Math.abs(a[i - 1]![i - 1]!) + Math.abs(a[i]![i]!))) {
2363
+ a[i]![i - 1] = 0;
2364
+ if (i === remaining - 1) {
2365
+ eigenvals.push(a[remaining - 1]![remaining - 1]!);
2366
+ remaining--;
2367
+ converged = true;
2368
+ break;
2369
+ }
2370
+ }
2371
+ }
2372
+
2373
+ if (converged) continue;
2374
+ if (remaining <= 1) break;
2375
+
2376
+ // Wilkinson shift
2377
+ const d = (a[remaining - 2]![remaining - 2]! - a[remaining - 1]![remaining - 1]!) / 2;
2378
+ const sign = d >= 0 ? 1 : -1;
2379
+ const mu = a[remaining - 1]![remaining - 1]! -
2380
+ sign * a[remaining - 1]![remaining - 2]! * a[remaining - 1]![remaining - 2]! /
2381
+ (Math.abs(d) + Math.sqrt(d * d + a[remaining - 1]![remaining - 2]! * a[remaining - 1]![remaining - 2]!));
2382
+
2383
+ // QR step with shift
2384
+ let x = a[0]![0]! - mu;
2385
+ let z = a[1]![0]!;
2386
+
2387
+ for (let k = 0; k < remaining - 1; k++) {
2388
+ // Givens rotation
2389
+ let r = Math.sqrt(x * x + z * z);
2390
+ if (r < EPSILON) {
2391
+ r = EPSILON;
2392
+ }
2393
+ const c = x / r;
2394
+ const s = z / r;
2395
+
2396
+ // Apply rotation from left
2397
+ for (let j = Math.max(0, k - 1); j < remaining; j++) {
2398
+ const temp = c * a[k]![j]! + s * a[k + 1]![j]!;
2399
+ a[k + 1]![j] = -s * a[k]![j]! + c * a[k + 1]![j]!;
2400
+ a[k]![j] = temp;
2401
+ }
2402
+
2403
+ // Apply rotation from right
2404
+ for (let i = 0; i < Math.min(k + 3, remaining); i++) {
2405
+ const temp = c * a[i]![k]! + s * a[i]![k + 1]!;
2406
+ a[i]![k + 1] = -s * a[i]![k]! + c * a[i]![k + 1]!;
2407
+ a[i]![k] = temp;
2408
+ }
2409
+
2410
+ if (k < remaining - 2) {
2411
+ x = a[k + 1]![k]!;
2412
+ z = a[k + 2]![k]!;
2413
+ }
2414
+ }
2415
+ }
2416
+
2417
+ // Extract remaining eigenvalues from diagonal
2418
+ for (let i = 0; i < remaining; i++) {
2419
+ eigenvals.push(a[i]![i]!);
2420
+ }
2421
+
2422
+ // Sort eigenvalues in descending order by absolute value
2423
+ eigenvals.sort((a, b) => Math.abs(b) - Math.abs(a));
2424
+
2425
+ return eigenvals;
2426
+ }
2427
+
2428
+ /**
2429
+ * Matrix eigenvectors
2430
+ *
2431
+ * Returns a matrix of eigenvectors, where each column is an eigenvector
2432
+ * corresponding to an eigenvalue.
2433
+ *
2434
+ * @param id - A matrix object (must be square)
2435
+ * @returns A new matrix where columns are eigenvectors
2436
+ *
2437
+ * @remarks
2438
+ * Uses inverse iteration method to compute eigenvectors from eigenvalues.
2439
+ * Eigenvectors are normalized to unit length.
2440
+ * Time complexity: O(n³)
2441
+ *
2442
+ * @example
2443
+ * ```typescript
2444
+ * // Create a 2x2 matrix
2445
+ * const m1 = matrix.new_matrix(2, 2, 1);
2446
+ * matrix.set(m1, 0, 0, 2);
2447
+ * matrix.set(m1, 0, 1, 4);
2448
+ * matrix.set(m1, 1, 0, 6);
2449
+ * matrix.set(m1, 1, 1, 8);
2450
+ *
2451
+ * const evecs = matrix.eigenvectors(m1);
2452
+ * // Each column is an eigenvector
2453
+ * ```
2454
+ */
2455
+ export function eigenvectors(id: PineMatrix<float>): PineMatrix<float> {
2456
+ if (!is_square(id)) {
2457
+ throw new Error(`Matrix must be square for eigenvector calculation: ${id.rows}x${id.columns}`);
2458
+ }
2459
+
2460
+ const n = id.rows;
2461
+
2462
+ if (n === 0) {
2463
+ return new_matrix<float>(0, 0, 0);
2464
+ }
2465
+
2466
+ // Get eigenvalues first
2467
+ const evals = eigenvalues(id);
2468
+
2469
+ // For each eigenvalue, compute eigenvector using inverse iteration
2470
+ const vectors: float[][] = [];
2471
+
2472
+ for (let i = 0; i < n; i++) {
2473
+ const lambda = evals[i]!;
2474
+ const vec = inverseIteration(id, lambda);
2475
+ vectors.push(vec);
2476
+ }
2477
+
2478
+ // Transpose to get eigenvectors as columns
2479
+ const result: float[][] = [];
2480
+ for (let i = 0; i < n; i++) {
2481
+ const row: float[] = [];
2482
+ for (let j = 0; j < n; j++) {
2483
+ row.push(vectors[j]![i]!);
2484
+ }
2485
+ result.push(row);
2486
+ }
2487
+
2488
+ return {
2489
+ rows: n,
2490
+ columns: n,
2491
+ data: result
2492
+ };
2493
+ }
2494
+
2495
+ /**
2496
+ * Helper: Inverse iteration for eigenvector computation
2497
+ */
2498
+ function inverseIteration(m: PineMatrix<float>, lambda: float): float[] {
2499
+ const n = m.rows;
2500
+
2501
+ // Create (A - λI)
2502
+ const shifted: float[][] = m.data.map((row, i) =>
2503
+ row.map((val, j) => i === j ? val - lambda : val)
2504
+ );
2505
+
2506
+ // Add small perturbation to avoid singular matrix
2507
+ for (let i = 0; i < n; i++) {
2508
+ if (Math.abs(shifted[i]![i]!) < EPSILON) {
2509
+ shifted[i]![i] = EPSILON;
2510
+ }
2511
+ }
2512
+
2513
+ // Initialize random vector
2514
+ let v: float[] = new Array(n).fill(1);
2515
+
2516
+ // Iterate
2517
+ for (let iter = 0; iter < 50; iter++) {
2518
+ // Solve (A - λI) * w = v using LU decomposition
2519
+ const w = solveLinearSystem(shifted, v);
2520
+
2521
+ // Normalize
2522
+ let norm = 0;
2523
+ for (let i = 0; i < n; i++) {
2524
+ norm += w[i]! * w[i]!;
2525
+ }
2526
+ norm = Math.sqrt(norm);
2527
+
2528
+ if (norm < EPSILON) {
2529
+ return v;
2530
+ }
2531
+
2532
+ const newV: float[] = [];
2533
+ for (let i = 0; i < n; i++) {
2534
+ newV.push(w[i]! / norm);
2535
+ }
2536
+
2537
+ // Check convergence
2538
+ let diff = 0;
2539
+ for (let i = 0; i < n; i++) {
2540
+ diff += Math.abs(Math.abs(newV[i]!) - Math.abs(v[i]!));
2541
+ }
2542
+
2543
+ v = newV;
2544
+
2545
+ if (diff < EPSILON) {
2546
+ break;
2547
+ }
2548
+ }
2549
+
2550
+ return v;
2551
+ }
2552
+
2553
+ /**
2554
+ * Helper: Solve linear system Ax = b using Gaussian elimination
2555
+ */
2556
+ function solveLinearSystem(a: float[][], b: float[]): float[] {
2557
+ const n = a.length;
2558
+
2559
+ // Create augmented matrix
2560
+ const aug: float[][] = a.map((row, i) => [...row, b[i]!]);
2561
+
2562
+ // Forward elimination with partial pivoting
2563
+ for (let col = 0; col < n; col++) {
2564
+ // Find pivot
2565
+ let maxRow = col;
2566
+ let maxVal = Math.abs(aug[col]![col]!);
2567
+ for (let row = col + 1; row < n; row++) {
2568
+ const absVal = Math.abs(aug[row]![col]!);
2569
+ if (absVal > maxVal) {
2570
+ maxVal = absVal;
2571
+ maxRow = row;
2572
+ }
2573
+ }
2574
+
2575
+ // Swap rows
2576
+ if (maxRow !== col) {
2577
+ const temp = aug[col]!;
2578
+ aug[col] = aug[maxRow]!;
2579
+ aug[maxRow] = temp;
2580
+ }
2581
+
2582
+ const pivot = aug[col]![col]!;
2583
+ if (Math.abs(pivot) < EPSILON) {
2584
+ continue;
2585
+ }
2586
+
2587
+ // Eliminate
2588
+ for (let row = col + 1; row < n; row++) {
2589
+ const factor = aug[row]![col]! / pivot;
2590
+ for (let j = col; j <= n; j++) {
2591
+ aug[row]![j] = aug[row]![j]! - factor * aug[col]![j]!;
2592
+ }
2593
+ }
2594
+ }
2595
+
2596
+ // Back substitution
2597
+ const x: float[] = new Array(n).fill(0);
2598
+ for (let i = n - 1; i >= 0; i--) {
2599
+ let sum = aug[i]![n]!;
2600
+ for (let j = i + 1; j < n; j++) {
2601
+ sum -= aug[i]![j]! * x[j]!;
2602
+ }
2603
+ const diag = aug[i]![i]!;
2604
+ x[i] = Math.abs(diag) < EPSILON ? 0 : sum / diag;
2605
+ }
2606
+
2607
+ return x;
2608
+ }
2609
+
2610
+ /**
2611
+ * Kronecker product
2612
+ *
2613
+ * Computes the Kronecker (tensor) product of two matrices.
2614
+ * Each element of id1 is multiplied by the entire id2 matrix.
2615
+ *
2616
+ * @param id1 - First matrix object
2617
+ * @param id2 - Second matrix object
2618
+ * @returns A new matrix containing the Kronecker product
2619
+ *
2620
+ * @remarks
2621
+ * Result size: (m₁×m₂) rows by (n₁×n₂) columns.
2622
+ * Time complexity: O(m₁×m₂×n₁×n₂)
2623
+ *
2624
+ * @example
2625
+ * ```typescript
2626
+ * // Create two 2x2 matrices
2627
+ * const m1 = matrix.new_matrix(2, 2, 1);
2628
+ * const m2 = matrix.new_matrix(2, 2, 2);
2629
+ *
2630
+ * const m3 = matrix.kron(m1, m2);
2631
+ * // Result is a 4x4 matrix
2632
+ * ```
2633
+ */
2634
+ export function kron(id1: PineMatrix<float>, id2: PineMatrix<float>): PineMatrix<float> {
2635
+ const m1 = id1.rows;
2636
+ const n1 = id1.columns;
2637
+ const m2 = id2.rows;
2638
+ const n2 = id2.columns;
2639
+
2640
+ const resultRows = m1 * m2;
2641
+ const resultCols = n1 * n2;
2642
+ const data: float[][] = [];
2643
+
2644
+ for (let i = 0; i < resultRows; i++) {
2645
+ data.push(new Array(resultCols).fill(0));
2646
+ }
2647
+
2648
+ for (let i1 = 0; i1 < m1; i1++) {
2649
+ for (let j1 = 0; j1 < n1; j1++) {
2650
+ const a = id1.data[i1]![j1]!;
2651
+ for (let i2 = 0; i2 < m2; i2++) {
2652
+ for (let j2 = 0; j2 < n2; j2++) {
2653
+ const row = i1 * m2 + i2;
2654
+ const col = j1 * n2 + j2;
2655
+ data[row]![col] = a * id2.data[i2]![j2]!;
2656
+ }
2657
+ }
2658
+ }
2659
+ }
2660
+
2661
+ return {
2662
+ rows: resultRows,
2663
+ columns: resultCols,
2664
+ data
2665
+ };
2666
+ }
2667
+
2668
+ /**
2669
+ * Create matrix of user-defined type
2670
+ *
2671
+ * Creates a new matrix that can hold user-defined types.
2672
+ * This is a placeholder that functions identically to new_matrix() for now,
2673
+ * as JavaScript doesn't have the same type system as PineScript.
2674
+ *
2675
+ * @param rows - Initial row count
2676
+ * @param columns - Initial column count
2677
+ * @param initial_value - Initial value for all elements
2678
+ * @returns A new matrix object
2679
+ *
2680
+ * @remarks
2681
+ * In PineScript, this is used for matrices containing user-defined types (UDTs).
2682
+ * In JavaScript, this behaves the same as new_matrix() since type handling
2683
+ * is done at runtime.
2684
+ *
2685
+ * @example
2686
+ * ```typescript
2687
+ * // Create a 2x2 matrix that could hold any type
2688
+ * const m = matrix.newtype(2, 2, { name: 'default', value: 0 });
2689
+ * ```
2690
+ */
2691
+ export function newtype<T>(
2692
+ rows: simple_int = 0,
2693
+ columns: simple_int = 0,
2694
+ initial_value?: T
2695
+ ): PineMatrix<T> {
2696
+ return new_matrix(rows, columns, initial_value);
2697
+ }