universal-physics-tensor 10.0.0 → 12.0.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 (835) hide show
  1. package/README.md +39 -36
  2. package/bin/upt.mjs +13 -1
  3. package/data/applied-cases.json +1892 -0
  4. package/data/applied-cases.schema.json +194 -0
  5. package/data/atlas/atlas.json +25 -25
  6. package/data/atlas/atlas.jsonld +1 -1
  7. package/data/atlas/diffusion.json +6 -6
  8. package/data/atlas/oscillators.json +7 -7
  9. package/data/atlas/waves.json +14 -14
  10. package/data/atlas/witness-results.json +11 -11
  11. package/data/bridge-catalog.json +389 -230
  12. package/data/bridge-catalog.schema.json +45 -7
  13. package/data/units.json +6 -25
  14. package/dist/atlas/applicability.d.ts.map +1 -1
  15. package/dist/atlas/applicability.js +21 -15
  16. package/dist/atlas/applicability.js.map +1 -1
  17. package/dist/atlas/benchmark/hybrid-retrieval.d.ts +9 -1
  18. package/dist/atlas/benchmark/hybrid-retrieval.d.ts.map +1 -1
  19. package/dist/atlas/benchmark/hybrid-retrieval.js +15 -13
  20. package/dist/atlas/benchmark/hybrid-retrieval.js.map +1 -1
  21. package/dist/atlas/benchmark/loader.js +2 -2
  22. package/dist/atlas/benchmark/loader.js.map +1 -1
  23. package/dist/atlas/benchmark/stats.d.ts +2 -2
  24. package/dist/atlas/benchmark/stats.d.ts.map +1 -1
  25. package/dist/atlas/benchmark/stats.js +9 -15
  26. package/dist/atlas/benchmark/stats.js.map +1 -1
  27. package/dist/atlas/catalog-formal-ref.d.ts +26 -3
  28. package/dist/atlas/catalog-formal-ref.d.ts.map +1 -1
  29. package/dist/atlas/catalog-formal-ref.js +52 -5
  30. package/dist/atlas/catalog-formal-ref.js.map +1 -1
  31. package/dist/atlas/chain-pipeline.d.ts.map +1 -1
  32. package/dist/atlas/chain-pipeline.js +7 -8
  33. package/dist/atlas/chain-pipeline.js.map +1 -1
  34. package/dist/atlas/diffusion/bridges-closure.d.ts +0 -4
  35. package/dist/atlas/diffusion/bridges-closure.d.ts.map +1 -1
  36. package/dist/atlas/diffusion/bridges-closure.js +8 -12
  37. package/dist/atlas/diffusion/bridges-closure.js.map +1 -1
  38. package/dist/atlas/diffusion/bridges.d.ts.map +1 -1
  39. package/dist/atlas/diffusion/bridges.js +27 -39
  40. package/dist/atlas/diffusion/bridges.js.map +1 -1
  41. package/dist/atlas/diffusion/dimensions.d.ts +6 -14
  42. package/dist/atlas/diffusion/dimensions.d.ts.map +1 -1
  43. package/dist/atlas/diffusion/dimensions.js +8 -16
  44. package/dist/atlas/diffusion/dimensions.js.map +1 -1
  45. package/dist/atlas/diffusion/models.d.ts +3 -3
  46. package/dist/atlas/diffusion/models.d.ts.map +1 -1
  47. package/dist/atlas/diffusion/models.js +5 -10
  48. package/dist/atlas/diffusion/models.js.map +1 -1
  49. package/dist/atlas/diffusion/numerics.d.ts +16 -4
  50. package/dist/atlas/diffusion/numerics.d.ts.map +1 -1
  51. package/dist/atlas/diffusion/numerics.js +38 -24
  52. package/dist/atlas/diffusion/numerics.js.map +1 -1
  53. package/dist/atlas/link-prediction.d.ts +106 -3
  54. package/dist/atlas/link-prediction.d.ts.map +1 -1
  55. package/dist/atlas/link-prediction.js +212 -66
  56. package/dist/atlas/link-prediction.js.map +1 -1
  57. package/dist/atlas/oscillators/bridges-coarse.d.ts.map +1 -1
  58. package/dist/atlas/oscillators/bridges-coarse.js +7 -11
  59. package/dist/atlas/oscillators/bridges-coarse.js.map +1 -1
  60. package/dist/atlas/oscillators/bridges-exact.d.ts.map +1 -1
  61. package/dist/atlas/oscillators/bridges-exact.js +6 -7
  62. package/dist/atlas/oscillators/bridges-exact.js.map +1 -1
  63. package/dist/atlas/oscillators/bridges-limits.d.ts +3 -16
  64. package/dist/atlas/oscillators/bridges-limits.d.ts.map +1 -1
  65. package/dist/atlas/oscillators/bridges-limits.js +23 -34
  66. package/dist/atlas/oscillators/bridges-limits.js.map +1 -1
  67. package/dist/atlas/oscillators/dimensions.d.ts +9 -21
  68. package/dist/atlas/oscillators/dimensions.d.ts.map +1 -1
  69. package/dist/atlas/oscillators/dimensions.js +9 -21
  70. package/dist/atlas/oscillators/dimensions.js.map +1 -1
  71. package/dist/atlas/oscillators/limit-witnesses.d.ts +2 -2
  72. package/dist/atlas/oscillators/limit-witnesses.d.ts.map +1 -1
  73. package/dist/atlas/oscillators/limit-witnesses.js +17 -15
  74. package/dist/atlas/oscillators/limit-witnesses.js.map +1 -1
  75. package/dist/atlas/oscillators/models.d.ts.map +1 -1
  76. package/dist/atlas/oscillators/models.js +2 -6
  77. package/dist/atlas/oscillators/models.js.map +1 -1
  78. package/dist/atlas/oscillators/pendulum-motion.d.ts +29 -6
  79. package/dist/atlas/oscillators/pendulum-motion.d.ts.map +1 -1
  80. package/dist/atlas/oscillators/pendulum-motion.js +60 -40
  81. package/dist/atlas/oscillators/pendulum-motion.js.map +1 -1
  82. package/dist/atlas/oscillators/phase-translation.d.ts +0 -11
  83. package/dist/atlas/oscillators/phase-translation.d.ts.map +1 -1
  84. package/dist/atlas/oscillators/phase-translation.js +3 -4
  85. package/dist/atlas/oscillators/phase-translation.js.map +1 -1
  86. package/dist/atlas/oscillators/position-translation.d.ts +68 -7
  87. package/dist/atlas/oscillators/position-translation.d.ts.map +1 -1
  88. package/dist/atlas/oscillators/position-translation.js +123 -12
  89. package/dist/atlas/oscillators/position-translation.js.map +1 -1
  90. package/dist/atlas/oscillators/rejections.d.ts +0 -2
  91. package/dist/atlas/oscillators/rejections.d.ts.map +1 -1
  92. package/dist/atlas/oscillators/rejections.js +0 -7
  93. package/dist/atlas/oscillators/rejections.js.map +1 -1
  94. package/dist/atlas/physjs-entries.generated.d.ts +35 -25
  95. package/dist/atlas/physjs-entries.generated.d.ts.map +1 -1
  96. package/dist/atlas/physjs-entries.generated.js +37 -25
  97. package/dist/atlas/physjs-entries.generated.js.map +1 -1
  98. package/dist/atlas/physjs-ref.d.ts +34 -31
  99. package/dist/atlas/physjs-ref.d.ts.map +1 -1
  100. package/dist/atlas/physjs-ref.js +55 -53
  101. package/dist/atlas/physjs-ref.js.map +1 -1
  102. package/dist/atlas/physjs-reviewed.d.ts +1 -1
  103. package/dist/atlas/physjs-reviewed.js +15 -15
  104. package/dist/atlas/physjs-reviewed.js.map +1 -1
  105. package/dist/atlas/poster/statements.d.ts +0 -19
  106. package/dist/atlas/poster/statements.d.ts.map +1 -1
  107. package/dist/atlas/poster/statements.js +1 -1
  108. package/dist/atlas/poster/statements.js.map +1 -1
  109. package/dist/atlas/proof-target.d.ts +1 -1
  110. package/dist/atlas/proof-target.js +1 -1
  111. package/dist/atlas/proof-target.js.map +1 -1
  112. package/dist/atlas/regime.d.ts +1 -1
  113. package/dist/atlas/regime.d.ts.map +1 -1
  114. package/dist/atlas/regime.js +1 -1
  115. package/dist/atlas/regime.js.map +1 -1
  116. package/dist/atlas/text-overlap.d.ts +23 -0
  117. package/dist/atlas/text-overlap.d.ts.map +1 -0
  118. package/dist/atlas/text-overlap.js +41 -0
  119. package/dist/atlas/text-overlap.js.map +1 -0
  120. package/dist/atlas/waves/bridges-closure.d.ts.map +1 -1
  121. package/dist/atlas/waves/bridges-closure.js +2 -6
  122. package/dist/atlas/waves/bridges-closure.js.map +1 -1
  123. package/dist/atlas/waves/bridges.d.ts.map +1 -1
  124. package/dist/atlas/waves/bridges.js +32 -48
  125. package/dist/atlas/waves/bridges.js.map +1 -1
  126. package/dist/atlas/waves/models.d.ts +5 -6
  127. package/dist/atlas/waves/models.d.ts.map +1 -1
  128. package/dist/atlas/waves/models.js +7 -13
  129. package/dist/atlas/waves/models.js.map +1 -1
  130. package/dist/atlas/waves/numerics.d.ts.map +1 -1
  131. package/dist/atlas/waves/numerics.js +10 -3
  132. package/dist/atlas/waves/numerics.js.map +1 -1
  133. package/dist/atlas/witness-numeric.d.ts +30 -0
  134. package/dist/atlas/witness-numeric.d.ts.map +1 -1
  135. package/dist/atlas/witness-numeric.js +53 -0
  136. package/dist/atlas/witness-numeric.js.map +1 -1
  137. package/dist/atlas/witness-specs.d.ts.map +1 -1
  138. package/dist/atlas/witness-specs.js +19 -0
  139. package/dist/atlas/witness-specs.js.map +1 -1
  140. package/dist/atlas/witness-symbolic.d.ts +75 -3
  141. package/dist/atlas/witness-symbolic.d.ts.map +1 -1
  142. package/dist/atlas/witness-symbolic.js +116 -10
  143. package/dist/atlas/witness-symbolic.js.map +1 -1
  144. package/dist/bridges/catalog-load.d.ts.map +1 -1
  145. package/dist/bridges/catalog-load.js +13 -8
  146. package/dist/bridges/catalog-load.js.map +1 -1
  147. package/dist/bridges/catalog-types.d.ts +26 -2
  148. package/dist/bridges/catalog-types.d.ts.map +1 -1
  149. package/dist/bridges/catalog-types.js +11 -1
  150. package/dist/bridges/catalog-types.js.map +1 -1
  151. package/dist/bridges/evaluation-errors.d.ts +31 -1
  152. package/dist/bridges/evaluation-errors.d.ts.map +1 -1
  153. package/dist/bridges/evaluation-errors.js +20 -2
  154. package/dist/bridges/evaluation-errors.js.map +1 -1
  155. package/dist/bridges/evaluator-inputs.d.ts.map +1 -1
  156. package/dist/bridges/evaluator-inputs.js +7 -5
  157. package/dist/bridges/evaluator-inputs.js.map +1 -1
  158. package/dist/bridges/evaluators.d.ts.map +1 -1
  159. package/dist/bridges/evaluators.js +27 -12
  160. package/dist/bridges/evaluators.js.map +1 -1
  161. package/dist/bridges/expr-parse.d.ts +11 -0
  162. package/dist/bridges/expr-parse.d.ts.map +1 -1
  163. package/dist/bridges/expr-parse.js +14 -5
  164. package/dist/bridges/expr-parse.js.map +1 -1
  165. package/dist/bridges/holds.d.ts +35 -3
  166. package/dist/bridges/holds.d.ts.map +1 -1
  167. package/dist/bridges/holds.js +117 -23
  168. package/dist/bridges/holds.js.map +1 -1
  169. package/dist/bridges/notices.d.ts.map +1 -1
  170. package/dist/bridges/notices.js +5 -5
  171. package/dist/bridges/notices.js.map +1 -1
  172. package/dist/bridges/relation-eval.d.ts +4 -4
  173. package/dist/bridges/relation-eval.d.ts.map +1 -1
  174. package/dist/bridges/relation-eval.js +15 -16
  175. package/dist/bridges/relation-eval.js.map +1 -1
  176. package/dist/bridges/sensitivity.d.ts.map +1 -1
  177. package/dist/bridges/sensitivity.js +3 -3
  178. package/dist/bridges/sensitivity.js.map +1 -1
  179. package/dist/bridges/validity.d.ts +33 -0
  180. package/dist/bridges/validity.d.ts.map +1 -0
  181. package/dist/bridges/validity.js +67 -0
  182. package/dist/bridges/validity.js.map +1 -0
  183. package/dist/canonical/entries/atomic.js +1 -3
  184. package/dist/canonical/entries/atomic.js.map +1 -1
  185. package/dist/canonical/entries/condensed-matter.d.ts.map +1 -1
  186. package/dist/canonical/entries/condensed-matter.js +4 -5
  187. package/dist/canonical/entries/condensed-matter.js.map +1 -1
  188. package/dist/canonical/entries/dimensional-classics.d.ts.map +1 -1
  189. package/dist/canonical/entries/dimensional-classics.js +3 -4
  190. package/dist/canonical/entries/dimensional-classics.js.map +1 -1
  191. package/dist/canonical/entries/electromagnetism.d.ts.map +1 -1
  192. package/dist/canonical/entries/electromagnetism.js +4 -10
  193. package/dist/canonical/entries/electromagnetism.js.map +1 -1
  194. package/dist/canonical/entries/fluids-waves.d.ts.map +1 -1
  195. package/dist/canonical/entries/fluids-waves.js +3 -7
  196. package/dist/canonical/entries/fluids-waves.js.map +1 -1
  197. package/dist/canonical/entries/mechanics.d.ts.map +1 -1
  198. package/dist/canonical/entries/mechanics.js +4 -6
  199. package/dist/canonical/entries/mechanics.js.map +1 -1
  200. package/dist/canonical/entries/nonmonomial.d.ts.map +1 -1
  201. package/dist/canonical/entries/nonmonomial.js +9 -17
  202. package/dist/canonical/entries/nonmonomial.js.map +1 -1
  203. package/dist/canonical/entries/relativity.d.ts.map +1 -1
  204. package/dist/canonical/entries/relativity.js +6 -6
  205. package/dist/canonical/entries/relativity.js.map +1 -1
  206. package/dist/canonical/entries/thermo-nuclear-cosmo.d.ts.map +1 -1
  207. package/dist/canonical/entries/thermo-nuclear-cosmo.js +6 -10
  208. package/dist/canonical/entries/thermo-nuclear-cosmo.js.map +1 -1
  209. package/dist/canonical/fixed-points.d.ts +94 -0
  210. package/dist/canonical/fixed-points.d.ts.map +1 -0
  211. package/dist/canonical/fixed-points.js +81 -0
  212. package/dist/canonical/fixed-points.js.map +1 -0
  213. package/dist/canonical/linkage.d.ts.map +1 -1
  214. package/dist/canonical/linkage.js +25 -44
  215. package/dist/canonical/linkage.js.map +1 -1
  216. package/dist/canonical/normal-form.d.ts.map +1 -1
  217. package/dist/canonical/normal-form.js +5 -11
  218. package/dist/canonical/normal-form.js.map +1 -1
  219. package/dist/canonical/structural.d.ts +21 -21
  220. package/dist/canonical/structural.d.ts.map +1 -1
  221. package/dist/canonical/structural.js +40 -19
  222. package/dist/canonical/structural.js.map +1 -1
  223. package/dist/cases/catalog-checks.d.ts +10 -0
  224. package/dist/cases/catalog-checks.d.ts.map +1 -0
  225. package/dist/cases/catalog-checks.js +241 -0
  226. package/dist/cases/catalog-checks.js.map +1 -0
  227. package/dist/cases/catalog.d.ts +83 -0
  228. package/dist/cases/catalog.d.ts.map +1 -0
  229. package/dist/cases/catalog.js +118 -0
  230. package/dist/cases/catalog.js.map +1 -0
  231. package/dist/cases/engine.d.ts +13 -0
  232. package/dist/cases/engine.d.ts.map +1 -0
  233. package/dist/cases/engine.js +179 -0
  234. package/dist/cases/engine.js.map +1 -0
  235. package/dist/cases/index.d.ts.map +1 -1
  236. package/dist/cases/index.js +5 -7
  237. package/dist/cases/index.js.map +1 -1
  238. package/dist/cases/methods.d.ts +215 -0
  239. package/dist/cases/methods.d.ts.map +1 -0
  240. package/dist/cases/methods.js +743 -0
  241. package/dist/cases/methods.js.map +1 -0
  242. package/dist/cases/quadrature.d.ts +7 -9
  243. package/dist/cases/quadrature.d.ts.map +1 -1
  244. package/dist/cases/quadrature.js +28 -32
  245. package/dist/cases/quadrature.js.map +1 -1
  246. package/dist/cases/types.d.ts +12 -0
  247. package/dist/cases/types.d.ts.map +1 -1
  248. package/dist/cases/types.js.map +1 -1
  249. package/dist/cli/args.d.ts +25 -1
  250. package/dist/cli/args.d.ts.map +1 -1
  251. package/dist/cli/args.js +30 -8
  252. package/dist/cli/args.js.map +1 -1
  253. package/dist/cli/bindings.d.ts.map +1 -1
  254. package/dist/cli/bindings.js +5 -4
  255. package/dist/cli/bindings.js.map +1 -1
  256. package/dist/cli/command.d.ts +11 -1
  257. package/dist/cli/command.d.ts.map +1 -1
  258. package/dist/cli/command.js.map +1 -1
  259. package/dist/cli/commands/_atlas-map.d.ts +0 -9
  260. package/dist/cli/commands/_atlas-map.d.ts.map +1 -1
  261. package/dist/cli/commands/_atlas-map.js +8 -18
  262. package/dist/cli/commands/_atlas-map.js.map +1 -1
  263. package/dist/cli/commands/_atlas-route.d.ts.map +1 -1
  264. package/dist/cli/commands/_atlas-route.js +6 -2
  265. package/dist/cli/commands/_atlas-route.js.map +1 -1
  266. package/dist/cli/commands/_discovery-opts.d.ts +1 -0
  267. package/dist/cli/commands/_discovery-opts.d.ts.map +1 -1
  268. package/dist/cli/commands/_discovery-opts.js +9 -9
  269. package/dist/cli/commands/_discovery-opts.js.map +1 -1
  270. package/dist/cli/commands/atlas.d.ts.map +1 -1
  271. package/dist/cli/commands/atlas.js +8 -5
  272. package/dist/cli/commands/atlas.js.map +1 -1
  273. package/dist/cli/commands/audit.d.ts.map +1 -1
  274. package/dist/cli/commands/audit.js +8 -1
  275. package/dist/cli/commands/audit.js.map +1 -1
  276. package/dist/cli/commands/axes.d.ts.map +1 -1
  277. package/dist/cli/commands/axes.js +20 -1
  278. package/dist/cli/commands/axes.js.map +1 -1
  279. package/dist/cli/commands/confront.d.ts.map +1 -1
  280. package/dist/cli/commands/confront.js +8 -14
  281. package/dist/cli/commands/confront.js.map +1 -1
  282. package/dist/cli/commands/derive.d.ts.map +1 -1
  283. package/dist/cli/commands/derive.js +22 -22
  284. package/dist/cli/commands/derive.js.map +1 -1
  285. package/dist/cli/commands/discover.d.ts.map +1 -1
  286. package/dist/cli/commands/discover.js +122 -73
  287. package/dist/cli/commands/discover.js.map +1 -1
  288. package/dist/cli/commands/eval.d.ts.map +1 -1
  289. package/dist/cli/commands/eval.js +1 -0
  290. package/dist/cli/commands/eval.js.map +1 -1
  291. package/dist/cli/commands/evaluate.d.ts.map +1 -1
  292. package/dist/cli/commands/evaluate.js +67 -39
  293. package/dist/cli/commands/evaluate.js.map +1 -1
  294. package/dist/cli/commands/explain.d.ts.map +1 -1
  295. package/dist/cli/commands/explain.js +24 -3
  296. package/dist/cli/commands/explain.js.map +1 -1
  297. package/dist/cli/commands/ground.d.ts.map +1 -1
  298. package/dist/cli/commands/ground.js +7 -1
  299. package/dist/cli/commands/ground.js.map +1 -1
  300. package/dist/cli/commands/map.d.ts.map +1 -1
  301. package/dist/cli/commands/map.js +84 -11
  302. package/dist/cli/commands/map.js.map +1 -1
  303. package/dist/cli/commands/metric.d.ts.map +1 -1
  304. package/dist/cli/commands/metric.js +12 -9
  305. package/dist/cli/commands/metric.js.map +1 -1
  306. package/dist/cli/commands/path.d.ts +10 -0
  307. package/dist/cli/commands/path.d.ts.map +1 -1
  308. package/dist/cli/commands/path.js +25 -3
  309. package/dist/cli/commands/path.js.map +1 -1
  310. package/dist/cli/commands/probe.d.ts.map +1 -1
  311. package/dist/cli/commands/probe.js +59 -16
  312. package/dist/cli/commands/probe.js.map +1 -1
  313. package/dist/cli/commands/regime.d.ts.map +1 -1
  314. package/dist/cli/commands/regime.js +1 -0
  315. package/dist/cli/commands/regime.js.map +1 -1
  316. package/dist/cli/commands/retrieve.d.ts.map +1 -1
  317. package/dist/cli/commands/retrieve.js +1 -0
  318. package/dist/cli/commands/retrieve.js.map +1 -1
  319. package/dist/cli/commands/search.d.ts.map +1 -1
  320. package/dist/cli/commands/search.js +1 -0
  321. package/dist/cli/commands/search.js.map +1 -1
  322. package/dist/cli/commands/symbolic.d.ts.map +1 -1
  323. package/dist/cli/commands/symbolic.js +19 -28
  324. package/dist/cli/commands/symbolic.js.map +1 -1
  325. package/dist/cli/commands/testplan.d.ts.map +1 -1
  326. package/dist/cli/commands/testplan.js +4 -2
  327. package/dist/cli/commands/testplan.js.map +1 -1
  328. package/dist/cli/determination.d.ts +1 -0
  329. package/dist/cli/determination.d.ts.map +1 -1
  330. package/dist/cli/determination.js.map +1 -1
  331. package/dist/cli/expr-print.d.ts +0 -2
  332. package/dist/cli/expr-print.d.ts.map +1 -1
  333. package/dist/cli/expr-print.js +7 -31
  334. package/dist/cli/expr-print.js.map +1 -1
  335. package/dist/cli/flag-help.d.ts +1 -0
  336. package/dist/cli/flag-help.d.ts.map +1 -1
  337. package/dist/cli/flag-help.js +1 -0
  338. package/dist/cli/flag-help.js.map +1 -1
  339. package/dist/cli/graphs.d.ts +2 -0
  340. package/dist/cli/graphs.d.ts.map +1 -1
  341. package/dist/cli/graphs.js +1 -0
  342. package/dist/cli/graphs.js.map +1 -1
  343. package/dist/cli/main.d.ts +8 -0
  344. package/dist/cli/main.d.ts.map +1 -1
  345. package/dist/cli/main.js +19 -3
  346. package/dist/cli/main.js.map +1 -1
  347. package/dist/cli/numeric-flag.d.ts +12 -0
  348. package/dist/cli/numeric-flag.d.ts.map +1 -0
  349. package/dist/cli/numeric-flag.js +44 -0
  350. package/dist/cli/numeric-flag.js.map +1 -0
  351. package/dist/cli/output.d.ts +28 -0
  352. package/dist/cli/output.d.ts.map +1 -1
  353. package/dist/cli/output.js +23 -0
  354. package/dist/cli/output.js.map +1 -1
  355. package/dist/cli/record-reach.js +2 -2
  356. package/dist/cli/record-reach.js.map +1 -1
  357. package/dist/cli/record-tables.d.ts.map +1 -1
  358. package/dist/cli/record-tables.js +6 -5
  359. package/dist/cli/record-tables.js.map +1 -1
  360. package/dist/cli/record.d.ts +1 -5
  361. package/dist/cli/record.d.ts.map +1 -1
  362. package/dist/cli/record.js +9 -8
  363. package/dist/cli/record.js.map +1 -1
  364. package/dist/cli/search-index.d.ts.map +1 -1
  365. package/dist/cli/search-index.js +7 -6
  366. package/dist/cli/search-index.js.map +1 -1
  367. package/dist/cli/statuses.d.ts +0 -2
  368. package/dist/cli/statuses.d.ts.map +1 -1
  369. package/dist/cli/statuses.js +12 -9
  370. package/dist/cli/statuses.js.map +1 -1
  371. package/dist/cli/stored-results.d.ts +7 -0
  372. package/dist/cli/stored-results.d.ts.map +1 -0
  373. package/dist/cli/stored-results.js +23 -0
  374. package/dist/cli/stored-results.js.map +1 -0
  375. package/dist/cli/version.d.ts +1 -0
  376. package/dist/cli/version.d.ts.map +1 -1
  377. package/dist/cli/version.js +8 -5
  378. package/dist/cli/version.js.map +1 -1
  379. package/dist/cli-api.d.ts +36 -5
  380. package/dist/cli-api.d.ts.map +1 -1
  381. package/dist/cli-api.js +30 -4
  382. package/dist/cli-api.js.map +1 -1
  383. package/dist/composition/algebraic-equivalence.d.ts +43 -0
  384. package/dist/composition/algebraic-equivalence.d.ts.map +1 -0
  385. package/dist/composition/algebraic-equivalence.js +115 -0
  386. package/dist/composition/algebraic-equivalence.js.map +1 -0
  387. package/dist/composition/axes.d.ts +0 -6
  388. package/dist/composition/axes.d.ts.map +1 -1
  389. package/dist/composition/axes.js +6 -6
  390. package/dist/composition/axes.js.map +1 -1
  391. package/dist/composition/axis-audit.d.ts +47 -20
  392. package/dist/composition/axis-audit.d.ts.map +1 -1
  393. package/dist/composition/axis-audit.js +82 -9
  394. package/dist/composition/axis-audit.js.map +1 -1
  395. package/dist/composition/bridge-analysis.d.ts +17 -0
  396. package/dist/composition/bridge-analysis.d.ts.map +1 -1
  397. package/dist/composition/bridge-analysis.js +102 -55
  398. package/dist/composition/bridge-analysis.js.map +1 -1
  399. package/dist/composition/canonical-compare.d.ts +40 -0
  400. package/dist/composition/canonical-compare.d.ts.map +1 -1
  401. package/dist/composition/canonical-compare.js +122 -24
  402. package/dist/composition/canonical-compare.js.map +1 -1
  403. package/dist/composition/canonical-graph.d.ts +3 -3
  404. package/dist/composition/canonical-graph.d.ts.map +1 -1
  405. package/dist/composition/canonical-graph.js +11 -38
  406. package/dist/composition/canonical-graph.js.map +1 -1
  407. package/dist/composition/canonical-json.js +2 -2
  408. package/dist/composition/canonical-json.js.map +1 -1
  409. package/dist/composition/catalog-graph.d.ts.map +1 -1
  410. package/dist/composition/catalog-graph.js +2 -5
  411. package/dist/composition/catalog-graph.js.map +1 -1
  412. package/dist/composition/chain-candidate.d.ts +8 -0
  413. package/dist/composition/chain-candidate.d.ts.map +1 -1
  414. package/dist/composition/chain-candidate.js +9 -2
  415. package/dist/composition/chain-candidate.js.map +1 -1
  416. package/dist/composition/chain-match.d.ts +6 -3
  417. package/dist/composition/chain-match.d.ts.map +1 -1
  418. package/dist/composition/chain-match.js +4 -1
  419. package/dist/composition/chain-match.js.map +1 -1
  420. package/dist/composition/chain-result.d.ts.map +1 -1
  421. package/dist/composition/chain-result.js +2 -14
  422. package/dist/composition/chain-result.js.map +1 -1
  423. package/dist/composition/compose-symbolic.d.ts.map +1 -1
  424. package/dist/composition/compose-symbolic.js +3 -2
  425. package/dist/composition/compose-symbolic.js.map +1 -1
  426. package/dist/composition/compose.d.ts.map +1 -1
  427. package/dist/composition/compose.js +13 -5
  428. package/dist/composition/compose.js.map +1 -1
  429. package/dist/composition/composition-recovery.d.ts.map +1 -1
  430. package/dist/composition/composition-recovery.js +4 -7
  431. package/dist/composition/composition-recovery.js.map +1 -1
  432. package/dist/composition/consequence.d.ts +15 -5
  433. package/dist/composition/consequence.d.ts.map +1 -1
  434. package/dist/composition/consequence.js +6 -4
  435. package/dist/composition/consequence.js.map +1 -1
  436. package/dist/composition/discovery.d.ts +129 -9
  437. package/dist/composition/discovery.d.ts.map +1 -1
  438. package/dist/composition/discovery.js +171 -67
  439. package/dist/composition/discovery.js.map +1 -1
  440. package/dist/composition/edge.d.ts +21 -2
  441. package/dist/composition/edge.d.ts.map +1 -1
  442. package/dist/composition/edge.js +23 -1
  443. package/dist/composition/edge.js.map +1 -1
  444. package/dist/composition/enumerate.d.ts.map +1 -1
  445. package/dist/composition/enumerate.js +18 -3
  446. package/dist/composition/enumerate.js.map +1 -1
  447. package/dist/composition/evaluate-relation.d.ts +35 -11
  448. package/dist/composition/evaluate-relation.d.ts.map +1 -1
  449. package/dist/composition/evaluate-relation.js +60 -39
  450. package/dist/composition/evaluate-relation.js.map +1 -1
  451. package/dist/composition/explain.d.ts +3 -12
  452. package/dist/composition/explain.d.ts.map +1 -1
  453. package/dist/composition/explain.js +7 -20
  454. package/dist/composition/explain.js.map +1 -1
  455. package/dist/composition/expr-eval.d.ts +1 -1
  456. package/dist/composition/expr-eval.d.ts.map +1 -1
  457. package/dist/composition/expr-eval.js +6 -15
  458. package/dist/composition/expr-eval.js.map +1 -1
  459. package/dist/composition/expr-simplify.d.ts +26 -14
  460. package/dist/composition/expr-simplify.d.ts.map +1 -1
  461. package/dist/composition/expr-simplify.js +64 -72
  462. package/dist/composition/expr-simplify.js.map +1 -1
  463. package/dist/composition/formula-shape.d.ts +23 -4
  464. package/dist/composition/formula-shape.d.ts.map +1 -1
  465. package/dist/composition/formula-shape.js +57 -17
  466. package/dist/composition/formula-shape.js.map +1 -1
  467. package/dist/composition/graph-structure.d.ts +98 -0
  468. package/dist/composition/graph-structure.d.ts.map +1 -0
  469. package/dist/composition/graph-structure.js +167 -0
  470. package/dist/composition/graph-structure.js.map +1 -0
  471. package/dist/composition/graph-viz-svg.d.ts.map +1 -1
  472. package/dist/composition/graph-viz-svg.js +1 -1
  473. package/dist/composition/graph-viz-svg.js.map +1 -1
  474. package/dist/composition/graph-viz.d.ts.map +1 -1
  475. package/dist/composition/graph-viz.js +8 -37
  476. package/dist/composition/graph-viz.js.map +1 -1
  477. package/dist/composition/grounding.d.ts.map +1 -1
  478. package/dist/composition/grounding.js +19 -7
  479. package/dist/composition/grounding.js.map +1 -1
  480. package/dist/composition/identifiability.d.ts +91 -4
  481. package/dist/composition/identifiability.d.ts.map +1 -1
  482. package/dist/composition/identifiability.js +363 -6
  483. package/dist/composition/identifiability.js.map +1 -1
  484. package/dist/composition/index.d.ts +8 -4
  485. package/dist/composition/index.d.ts.map +1 -1
  486. package/dist/composition/index.js +3 -2
  487. package/dist/composition/index.js.map +1 -1
  488. package/dist/composition/mathts-quiet.d.ts +7 -8
  489. package/dist/composition/mathts-quiet.d.ts.map +1 -1
  490. package/dist/composition/mathts-quiet.js +7 -16
  491. package/dist/composition/mathts-quiet.js.map +1 -1
  492. package/dist/composition/mathts-scalar-symbols.d.ts.map +1 -1
  493. package/dist/composition/mathts-scalar-symbols.js +2 -1
  494. package/dist/composition/mathts-scalar-symbols.js.map +1 -1
  495. package/dist/composition/own-equation-magnitude.d.ts +95 -0
  496. package/dist/composition/own-equation-magnitude.d.ts.map +1 -0
  497. package/dist/composition/own-equation-magnitude.js +270 -0
  498. package/dist/composition/own-equation-magnitude.js.map +1 -0
  499. package/dist/composition/probe/backend-protocol.d.ts +3 -0
  500. package/dist/composition/probe/backend-protocol.d.ts.map +1 -1
  501. package/dist/composition/probe/backend-protocol.js.map +1 -1
  502. package/dist/composition/probe/candidate-store.d.ts +1 -0
  503. package/dist/composition/probe/candidate-store.d.ts.map +1 -1
  504. package/dist/composition/probe/candidate-store.js +1 -0
  505. package/dist/composition/probe/candidate-store.js.map +1 -1
  506. package/dist/composition/probe/corpus.d.ts +8 -4
  507. package/dist/composition/probe/corpus.d.ts.map +1 -1
  508. package/dist/composition/probe/corpus.js +23 -12
  509. package/dist/composition/probe/corpus.js.map +1 -1
  510. package/dist/composition/probe/dataset.d.ts +18 -0
  511. package/dist/composition/probe/dataset.d.ts.map +1 -1
  512. package/dist/composition/probe/dataset.js +95 -50
  513. package/dist/composition/probe/dataset.js.map +1 -1
  514. package/dist/composition/probe/experiment-design.d.ts +7 -1
  515. package/dist/composition/probe/experiment-design.d.ts.map +1 -1
  516. package/dist/composition/probe/experiment-design.js +44 -24
  517. package/dist/composition/probe/experiment-design.js.map +1 -1
  518. package/dist/composition/probe/falsify.d.ts +2 -0
  519. package/dist/composition/probe/falsify.d.ts.map +1 -1
  520. package/dist/composition/probe/falsify.js +2 -0
  521. package/dist/composition/probe/falsify.js.map +1 -1
  522. package/dist/composition/probe/fit.d.ts +7 -0
  523. package/dist/composition/probe/fit.d.ts.map +1 -1
  524. package/dist/composition/probe/fit.js +46 -22
  525. package/dist/composition/probe/fit.js.map +1 -1
  526. package/dist/composition/probe/frontier.d.ts.map +1 -1
  527. package/dist/composition/probe/frontier.js +33 -15
  528. package/dist/composition/probe/frontier.js.map +1 -1
  529. package/dist/composition/probe/generator.d.ts +30 -1
  530. package/dist/composition/probe/generator.d.ts.map +1 -1
  531. package/dist/composition/probe/generator.js +58 -36
  532. package/dist/composition/probe/generator.js.map +1 -1
  533. package/dist/composition/probe/index.d.ts +14 -0
  534. package/dist/composition/probe/index.d.ts.map +1 -1
  535. package/dist/composition/probe/index.js +6 -0
  536. package/dist/composition/probe/index.js.map +1 -1
  537. package/dist/composition/probe/limits.d.ts +25 -1
  538. package/dist/composition/probe/limits.d.ts.map +1 -1
  539. package/dist/composition/probe/limits.js +53 -11
  540. package/dist/composition/probe/limits.js.map +1 -1
  541. package/dist/composition/probe/pipeline.d.ts +5 -0
  542. package/dist/composition/probe/pipeline.d.ts.map +1 -1
  543. package/dist/composition/probe/pipeline.js +73 -24
  544. package/dist/composition/probe/pipeline.js.map +1 -1
  545. package/dist/composition/probe/power-law.d.ts +121 -0
  546. package/dist/composition/probe/power-law.d.ts.map +1 -0
  547. package/dist/composition/probe/power-law.js +251 -0
  548. package/dist/composition/probe/power-law.js.map +1 -0
  549. package/dist/composition/probe/problem.d.ts +8 -4
  550. package/dist/composition/probe/problem.d.ts.map +1 -1
  551. package/dist/composition/probe/problem.js +177 -49
  552. package/dist/composition/probe/problem.js.map +1 -1
  553. package/dist/composition/probe/report.js +1 -1
  554. package/dist/composition/probe/report.js.map +1 -1
  555. package/dist/composition/probe/residual.d.ts +7 -1
  556. package/dist/composition/probe/residual.d.ts.map +1 -1
  557. package/dist/composition/probe/residual.js +10 -7
  558. package/dist/composition/probe/residual.js.map +1 -1
  559. package/dist/composition/probe/run-manifest.d.ts +1 -0
  560. package/dist/composition/probe/run-manifest.d.ts.map +1 -1
  561. package/dist/composition/probe/run-manifest.js.map +1 -1
  562. package/dist/composition/probe/scalar-search.d.ts +50 -0
  563. package/dist/composition/probe/scalar-search.d.ts.map +1 -0
  564. package/dist/composition/probe/scalar-search.js +169 -0
  565. package/dist/composition/probe/scalar-search.js.map +1 -0
  566. package/dist/composition/probe/scoring.d.ts +1 -0
  567. package/dist/composition/probe/scoring.d.ts.map +1 -1
  568. package/dist/composition/probe/scoring.js.map +1 -1
  569. package/dist/composition/probe/structure.d.ts +82 -17
  570. package/dist/composition/probe/structure.d.ts.map +1 -1
  571. package/dist/composition/probe/structure.js +129 -55
  572. package/dist/composition/probe/structure.js.map +1 -1
  573. package/dist/composition/probe/study.d.ts +31 -9
  574. package/dist/composition/probe/study.d.ts.map +1 -1
  575. package/dist/composition/probe/study.js +235 -184
  576. package/dist/composition/probe/study.js.map +1 -1
  577. package/dist/composition/probe/t-tail.d.ts +16 -0
  578. package/dist/composition/probe/t-tail.d.ts.map +1 -0
  579. package/dist/composition/probe/t-tail.js +29 -0
  580. package/dist/composition/probe/t-tail.js.map +1 -0
  581. package/dist/composition/probe/types.d.ts +3 -0
  582. package/dist/composition/probe/types.d.ts.map +1 -1
  583. package/dist/composition/probe/types.js.map +1 -1
  584. package/dist/composition/proposed-bridges.d.ts +52 -12
  585. package/dist/composition/proposed-bridges.d.ts.map +1 -1
  586. package/dist/composition/proposed-bridges.js +107 -60
  587. package/dist/composition/proposed-bridges.js.map +1 -1
  588. package/dist/composition/quantity-clusters.d.ts +48 -0
  589. package/dist/composition/quantity-clusters.d.ts.map +1 -0
  590. package/dist/composition/quantity-clusters.js +98 -0
  591. package/dist/composition/quantity-clusters.js.map +1 -0
  592. package/dist/composition/rational-exponent.d.ts +40 -0
  593. package/dist/composition/rational-exponent.d.ts.map +1 -0
  594. package/dist/composition/rational-exponent.js +65 -0
  595. package/dist/composition/rational-exponent.js.map +1 -0
  596. package/dist/composition/representative-values.d.ts +22 -0
  597. package/dist/composition/representative-values.d.ts.map +1 -1
  598. package/dist/composition/representative-values.js +29 -0
  599. package/dist/composition/representative-values.js.map +1 -1
  600. package/dist/composition/retrodiction.d.ts +15 -0
  601. package/dist/composition/retrodiction.d.ts.map +1 -1
  602. package/dist/composition/retrodiction.js +12 -4
  603. package/dist/composition/retrodiction.js.map +1 -1
  604. package/dist/composition/user-equation.d.ts +1 -0
  605. package/dist/composition/user-equation.d.ts.map +1 -1
  606. package/dist/composition/user-equation.js +3 -2
  607. package/dist/composition/user-equation.js.map +1 -1
  608. package/dist/core/assignment.d.ts +19 -0
  609. package/dist/core/assignment.d.ts.map +1 -0
  610. package/dist/core/assignment.js +19 -0
  611. package/dist/core/assignment.js.map +1 -0
  612. package/dist/core/compare.d.ts +32 -0
  613. package/dist/core/compare.d.ts.map +1 -0
  614. package/dist/core/compare.js +46 -0
  615. package/dist/core/compare.js.map +1 -0
  616. package/dist/core/constants.d.ts +42 -41
  617. package/dist/core/constants.d.ts.map +1 -1
  618. package/dist/core/constants.js +71 -51
  619. package/dist/core/constants.js.map +1 -1
  620. package/dist/core/data-file.d.ts +7 -0
  621. package/dist/core/data-file.d.ts.map +1 -1
  622. package/dist/core/data-file.js +17 -0
  623. package/dist/core/data-file.js.map +1 -1
  624. package/dist/core/format.d.ts +36 -0
  625. package/dist/core/format.d.ts.map +1 -0
  626. package/dist/core/format.js +39 -0
  627. package/dist/core/format.js.map +1 -0
  628. package/dist/core/hash.d.ts +14 -0
  629. package/dist/core/hash.d.ts.map +1 -0
  630. package/dist/core/hash.js +17 -0
  631. package/dist/core/hash.js.map +1 -0
  632. package/dist/core/json-schema.d.ts +2 -0
  633. package/dist/core/json-schema.d.ts.map +1 -1
  634. package/dist/core/json-schema.js +14 -13
  635. package/dist/core/json-schema.js.map +1 -1
  636. package/dist/core/labeled-tensor.d.ts.map +1 -1
  637. package/dist/core/labeled-tensor.js +0 -8
  638. package/dist/core/labeled-tensor.js.map +1 -1
  639. package/dist/core/mathts-read.d.ts +25 -0
  640. package/dist/core/mathts-read.d.ts.map +1 -0
  641. package/dist/core/mathts-read.js +51 -0
  642. package/dist/core/mathts-read.js.map +1 -0
  643. package/dist/core/tensor.d.ts.map +1 -1
  644. package/dist/core/tensor.js +24 -0
  645. package/dist/core/tensor.js.map +1 -1
  646. package/dist/core/types.d.ts +5 -5
  647. package/dist/diff/bridge-ast-gradient.d.ts +27 -23
  648. package/dist/diff/bridge-ast-gradient.d.ts.map +1 -1
  649. package/dist/diff/bridge-ast-gradient.js +75 -173
  650. package/dist/diff/bridge-ast-gradient.js.map +1 -1
  651. package/dist/diff/bridge-gradient.d.ts +19 -6
  652. package/dist/diff/bridge-gradient.d.ts.map +1 -1
  653. package/dist/diff/bridge-gradient.js +19 -11
  654. package/dist/diff/bridge-gradient.js.map +1 -1
  655. package/dist/diff/bridge-specs.d.ts.map +1 -1
  656. package/dist/diff/bridge-specs.js +3 -0
  657. package/dist/diff/bridge-specs.js.map +1 -1
  658. package/dist/dimensional/algebra.d.ts +18 -0
  659. package/dist/dimensional/algebra.d.ts.map +1 -1
  660. package/dist/dimensional/algebra.js +41 -1
  661. package/dist/dimensional/algebra.js.map +1 -1
  662. package/dist/dimensional/ast-builders.d.ts +7 -0
  663. package/dist/dimensional/ast-builders.d.ts.map +1 -1
  664. package/dist/dimensional/ast-builders.js +11 -0
  665. package/dist/dimensional/ast-builders.js.map +1 -1
  666. package/dist/dimensional/ast-leaves.d.ts +81 -0
  667. package/dist/dimensional/ast-leaves.d.ts.map +1 -0
  668. package/dist/dimensional/ast-leaves.js +146 -0
  669. package/dist/dimensional/ast-leaves.js.map +1 -0
  670. package/dist/dimensional/ast-types.d.ts +15 -0
  671. package/dist/dimensional/ast-types.d.ts.map +1 -1
  672. package/dist/dimensional/ast-types.js.map +1 -1
  673. package/dist/dimensional/buckingham.d.ts.map +1 -1
  674. package/dist/dimensional/buckingham.js +15 -27
  675. package/dist/dimensional/buckingham.js.map +1 -1
  676. package/dist/dimensional/constant-rows.js +9 -9
  677. package/dist/dimensional/constant-rows.js.map +1 -1
  678. package/dist/dimensional/curvature-composite.d.ts +1 -1
  679. package/dist/dimensional/curvature-composite.js.map +1 -1
  680. package/dist/dimensional/dimension-inference.d.ts.map +1 -1
  681. package/dist/dimensional/dimension-inference.js +1 -2
  682. package/dist/dimensional/dimension-inference.js.map +1 -1
  683. package/dist/dimensional/errors.d.ts +1 -1
  684. package/dist/dimensional/errors.d.ts.map +1 -1
  685. package/dist/dimensional/errors.js +1 -15
  686. package/dist/dimensional/errors.js.map +1 -1
  687. package/dist/dimensional/exact-scale.d.ts +24 -11
  688. package/dist/dimensional/exact-scale.d.ts.map +1 -1
  689. package/dist/dimensional/exact-scale.js +122 -130
  690. package/dist/dimensional/exact-scale.js.map +1 -1
  691. package/dist/dimensional/gauge-field.d.ts.map +1 -1
  692. package/dist/dimensional/gauge-field.js +2 -2
  693. package/dist/dimensional/gauge-field.js.map +1 -1
  694. package/dist/dimensional/hyphen-names.d.ts +12 -2
  695. package/dist/dimensional/hyphen-names.d.ts.map +1 -1
  696. package/dist/dimensional/hyphen-names.js +44 -19
  697. package/dist/dimensional/hyphen-names.js.map +1 -1
  698. package/dist/dimensional/mathts-unit-delegation.d.ts +29 -0
  699. package/dist/dimensional/mathts-unit-delegation.d.ts.map +1 -0
  700. package/dist/dimensional/mathts-unit-delegation.js +187 -0
  701. package/dist/dimensional/mathts-unit-delegation.js.map +1 -0
  702. package/dist/dimensional/mathts-unit-wrapper.d.ts +33 -0
  703. package/dist/dimensional/mathts-unit-wrapper.d.ts.map +1 -0
  704. package/dist/dimensional/mathts-unit-wrapper.js +190 -0
  705. package/dist/dimensional/mathts-unit-wrapper.js.map +1 -0
  706. package/dist/dimensional/metric.d.ts.map +1 -1
  707. package/dist/dimensional/metric.js +0 -1
  708. package/dist/dimensional/metric.js.map +1 -1
  709. package/dist/dimensional/scalar-lowering.d.ts +21 -0
  710. package/dist/dimensional/scalar-lowering.d.ts.map +1 -0
  711. package/dist/dimensional/scalar-lowering.js +45 -0
  712. package/dist/dimensional/scalar-lowering.js.map +1 -0
  713. package/dist/dimensional/symbolic-constants.d.ts +9 -0
  714. package/dist/dimensional/symbolic-constants.d.ts.map +1 -1
  715. package/dist/dimensional/symbolic-constants.js +13 -1
  716. package/dist/dimensional/symbolic-constants.js.map +1 -1
  717. package/dist/dimensional/types.d.ts +36 -0
  718. package/dist/dimensional/types.d.ts.map +1 -1
  719. package/dist/dimensional/types.js +45 -7
  720. package/dist/dimensional/types.js.map +1 -1
  721. package/dist/dimensional/unit-data.d.ts +5 -1
  722. package/dist/dimensional/unit-data.d.ts.map +1 -1
  723. package/dist/dimensional/unit-data.js +30 -6
  724. package/dist/dimensional/unit-data.js.map +1 -1
  725. package/dist/dimensional/units.d.ts +2 -0
  726. package/dist/dimensional/units.d.ts.map +1 -1
  727. package/dist/dimensional/units.js +59 -3
  728. package/dist/dimensional/units.js.map +1 -1
  729. package/dist/dimensional/validator.d.ts +2 -0
  730. package/dist/dimensional/validator.d.ts.map +1 -1
  731. package/dist/dimensional/validator.js.map +1 -1
  732. package/dist/index.d.ts +9 -3
  733. package/dist/index.d.ts.map +1 -1
  734. package/dist/index.js +10 -4
  735. package/dist/index.js.map +1 -1
  736. package/dist/numerical/christoffel-flat.d.ts.map +1 -1
  737. package/dist/numerical/christoffel-flat.js +3 -2
  738. package/dist/numerical/christoffel-flat.js.map +1 -1
  739. package/dist/numerical/connection-lowering-helpers.d.ts +3 -1
  740. package/dist/numerical/connection-lowering-helpers.d.ts.map +1 -1
  741. package/dist/numerical/connection-lowering-helpers.js +11 -15
  742. package/dist/numerical/connection-lowering-helpers.js.map +1 -1
  743. package/dist/numerical/covariant-eikonal.d.ts.map +1 -1
  744. package/dist/numerical/covariant-eikonal.js +34 -11
  745. package/dist/numerical/covariant-eikonal.js.map +1 -1
  746. package/dist/numerical/curvature-lowering-helpers.js +3 -2
  747. package/dist/numerical/curvature-lowering-helpers.js.map +1 -1
  748. package/dist/numerical/errors.d.ts.map +1 -1
  749. package/dist/numerical/errors.js +0 -3
  750. package/dist/numerical/errors.js.map +1 -1
  751. package/dist/numerical/finite-difference.d.ts +22 -0
  752. package/dist/numerical/finite-difference.d.ts.map +1 -0
  753. package/dist/numerical/finite-difference.js +27 -0
  754. package/dist/numerical/finite-difference.js.map +1 -0
  755. package/dist/numerical/geodesic-integrator.d.ts.map +1 -1
  756. package/dist/numerical/geodesic-integrator.js +22 -14
  757. package/dist/numerical/geodesic-integrator.js.map +1 -1
  758. package/dist/numerical/geometrized.d.ts.map +1 -1
  759. package/dist/numerical/geometrized.js +0 -1
  760. package/dist/numerical/geometrized.js.map +1 -1
  761. package/dist/numerical/mathts-engine.d.ts.map +1 -1
  762. package/dist/numerical/mathts-engine.js +10 -24
  763. package/dist/numerical/mathts-engine.js.map +1 -1
  764. package/dist/numerical/metric-inverse.d.ts.map +1 -1
  765. package/dist/numerical/metric-inverse.js +83 -46
  766. package/dist/numerical/metric-inverse.js.map +1 -1
  767. package/dist/numerical/null-ray-integrator.d.ts +2 -1
  768. package/dist/numerical/null-ray-integrator.d.ts.map +1 -1
  769. package/dist/numerical/null-ray-integrator.js +12 -12
  770. package/dist/numerical/null-ray-integrator.js.map +1 -1
  771. package/dist/numerical/painleve-gullstrand-metric.js +2 -2
  772. package/dist/numerical/painleve-gullstrand-metric.js.map +1 -1
  773. package/dist/numerical/pderiv.d.ts.map +1 -1
  774. package/dist/numerical/pderiv.js +2 -6
  775. package/dist/numerical/pderiv.js.map +1 -1
  776. package/dist/numerical/perihelion-finder.d.ts +0 -36
  777. package/dist/numerical/perihelion-finder.d.ts.map +1 -1
  778. package/dist/numerical/perihelion-finder.js +41 -87
  779. package/dist/numerical/perihelion-finder.js.map +1 -1
  780. package/dist/numerical/quadrature.d.ts.map +1 -1
  781. package/dist/numerical/quadrature.js +11 -13
  782. package/dist/numerical/quadrature.js.map +1 -1
  783. package/dist/numerical/rk4-trajectory.d.ts +10 -0
  784. package/dist/numerical/rk4-trajectory.d.ts.map +1 -0
  785. package/dist/numerical/rk4-trajectory.js +37 -0
  786. package/dist/numerical/rk4-trajectory.js.map +1 -0
  787. package/dist/numerical/schwarzschild.d.ts +14 -0
  788. package/dist/numerical/schwarzschild.d.ts.map +1 -0
  789. package/dist/numerical/schwarzschild.js +17 -0
  790. package/dist/numerical/schwarzschild.js.map +1 -0
  791. package/dist/numerical/spacetime-metrics.d.ts +12 -0
  792. package/dist/numerical/spacetime-metrics.d.ts.map +1 -1
  793. package/dist/numerical/spacetime-metrics.js +72 -56
  794. package/dist/numerical/spacetime-metrics.js.map +1 -1
  795. package/dist/numerical/statistics.d.ts +24 -0
  796. package/dist/numerical/statistics.d.ts.map +1 -0
  797. package/dist/numerical/statistics.js +52 -0
  798. package/dist/numerical/statistics.js.map +1 -0
  799. package/dist/numerical/strides.d.ts +3 -2
  800. package/dist/numerical/strides.d.ts.map +1 -1
  801. package/dist/numerical/strides.js +3 -10
  802. package/dist/numerical/strides.js.map +1 -1
  803. package/dist/numerical/tensor-engine.d.ts +21 -0
  804. package/dist/numerical/tensor-engine.d.ts.map +1 -1
  805. package/dist/numerical/tensor-engine.js +12 -0
  806. package/dist/numerical/tensor-engine.js.map +1 -1
  807. package/dist/relations/regime.d.ts +10 -0
  808. package/dist/relations/regime.d.ts.map +1 -1
  809. package/dist/relations/regime.js +18 -1
  810. package/dist/relations/regime.js.map +1 -1
  811. package/package.json +9 -12
  812. package/dist/cases/brownian-sphere.d.ts +0 -68
  813. package/dist/cases/brownian-sphere.d.ts.map +0 -1
  814. package/dist/cases/brownian-sphere.js +0 -354
  815. package/dist/cases/brownian-sphere.js.map +0 -1
  816. package/dist/cases/damped-resonator.d.ts +0 -23
  817. package/dist/cases/damped-resonator.d.ts.map +0 -1
  818. package/dist/cases/damped-resonator.js +0 -224
  819. package/dist/cases/damped-resonator.js.map +0 -1
  820. package/dist/cases/kepler-rv.d.ts +0 -13
  821. package/dist/cases/kepler-rv.d.ts.map +0 -1
  822. package/dist/cases/kepler-rv.js +0 -172
  823. package/dist/cases/kepler-rv.js.map +0 -1
  824. package/dist/cases/lumped-cooling.d.ts +0 -46
  825. package/dist/cases/lumped-cooling.d.ts.map +0 -1
  826. package/dist/cases/lumped-cooling.js +0 -261
  827. package/dist/cases/lumped-cooling.js.map +0 -1
  828. package/dist/cases/resistor-noise.d.ts +0 -14
  829. package/dist/cases/resistor-noise.d.ts.map +0 -1
  830. package/dist/cases/resistor-noise.js +0 -215
  831. package/dist/cases/resistor-noise.js.map +0 -1
  832. package/dist/cases/skin-depth.d.ts +0 -21
  833. package/dist/cases/skin-depth.d.ts.map +0 -1
  834. package/dist/cases/skin-depth.js +0 -174
  835. package/dist/cases/skin-depth.js.map +0 -1
@@ -1,16 +1,16 @@
1
1
  /**
2
2
  * Fixed-step classical RK4 integrator for affine-parameterized null
3
- * geodesics. No module under `src/` calls it: the covariant-eikonal path
4
- * (`src/numerical/covariant-eikonal.ts`) uses the symplectic
5
- * `integrateGeodesicGL4`, and the tests keep this one as the RK4 oracle
6
- * the atlas ODE helper is compared against. The fixed steps are MathTS
7
- * `solveODESystem` with `dt` set. Operates on plain `number[]` state
8
- * vectors, no TensorEngine dependency.
3
+ * geodesics, and the one-step RK4 the atlas and case modules call. The
4
+ * covariant-eikonal path (`src/numerical/covariant-eikonal.ts`) uses the
5
+ * symplectic `integrateGeodesicGL4` instead. The fixed steps are
6
+ * `rk4Trajectory` (`rk4-trajectory.ts`, MathTS `solveODESystem` with `dt`),
7
+ * the one owner of the step count; this module returns its last state.
8
+ * Operates on plain `number[]` state vectors, no TensorEngine dependency.
9
9
  *
10
10
  * @module numerical/null-ray-integrator
11
11
  */
12
- import { solveODESystem } from '@danielsimonjr/mathts-functions';
13
12
  import { NumericalBackendError } from './errors.js';
13
+ import { rk4Trajectory } from './rk4-trajectory.js';
14
14
  function checkLength(k, expected) {
15
15
  if (k.length !== expected) {
16
16
  throw new NumericalBackendError(`integrateRK4: ODE system returned a state vector of length ${k.length}, expected ${expected}`);
@@ -19,7 +19,8 @@ function checkLength(k, expected) {
19
19
  /**
20
20
  * Integrate `system` from affine parameter `lambda0` to `lambda1` in
21
21
  * `steps` fixed RK4 steps, starting from state `y0`. Returns the final
22
- * state vector. Classical 4th-order Runge-Kutta — global error O(h⁴).
22
+ * state vector. Classical 4th-order Runge-Kutta — global error O(h⁴). It takes
23
+ * exactly `steps` steps of (lambda1 − lambda0)/steps (`rk4Trajectory`).
23
24
  *
24
25
  * @internal — cross-module/test use only; not part of the consumer surface.
25
26
  */
@@ -27,13 +28,12 @@ export function integrateRK4(system, y0, lambda0, lambda1, steps) {
27
28
  if (!Number.isInteger(steps) || steps <= 0) {
28
29
  throw new NumericalBackendError(`integrateRK4: step count must be a positive integer, got ${steps}`);
29
30
  }
30
- const h = (lambda1 - lambda0) / steps;
31
31
  const yStart = [...y0];
32
- const sol = solveODESystem((lambda, y) => {
32
+ const states = rk4Trajectory((lambda, y) => {
33
33
  const k = system(lambda, y);
34
34
  checkLength(k, yStart.length);
35
35
  return k;
36
- }, yStart, [lambda0, lambda1], { dt: h });
37
- return [...(sol.y[sol.y.length - 1] ?? yStart)];
36
+ }, yStart, lambda0, lambda1, steps);
37
+ return states[states.length - 1] ?? yStart;
38
38
  }
39
39
  //# sourceMappingURL=null-ray-integrator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"null-ray-integrator.js","sourceRoot":"","sources":["../../src/numerical/null-ray-integrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAOpD,SAAS,WAAW,CAAC,CAAwB,EAAE,QAAgB;IAC7D,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,qBAAqB,CAC7B,8DAA8D,CAAC,CAAC,MAAM,cAAc,QAAQ,EAAE,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAiB,EACjB,EAAyB,EACzB,OAAe,EACf,OAAe,EACf,KAAa;IAEb,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,qBAAqB,CAAC,4DAA4D,KAAK,EAAE,CAAC,CAAC;IACvG,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,KAAK,CAAC;IACtC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IACvB,MAAM,GAAG,GAAG,cAAc,CACxB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACZ,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5B,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC;IACX,CAAC,EACD,MAAM,EACN,CAAC,OAAO,EAAE,OAAO,CAAC,EAClB,EAAE,EAAE,EAAE,CAAC,EAAE,CACV,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;AAClD,CAAC","sourcesContent":["/**\n * Fixed-step classical RK4 integrator for affine-parameterized null\n * geodesics. No module under `src/` calls it: the covariant-eikonal path\n * (`src/numerical/covariant-eikonal.ts`) uses the symplectic\n * `integrateGeodesicGL4`, and the tests keep this one as the RK4 oracle\n * the atlas ODE helper is compared against. The fixed steps are MathTS\n * `solveODESystem` with `dt` set. Operates on plain `number[]` state\n * vectors, no TensorEngine dependency.\n *\n * @module numerical/null-ray-integrator\n */\nimport { solveODESystem } from '@danielsimonjr/mathts-functions';\nimport { NumericalBackendError } from './errors.js';\n\n/** A first-order ODE system: dy/dλ = f(λ, y). `y` and the return are\n * state vectors of equal length.\n * v0.6.1: dropped export — was @internal-tagged with no external consumer. */\ntype ODESystem = (lambda: number, y: ReadonlyArray<number>) => number[];\n\nfunction checkLength(k: ReadonlyArray<number>, expected: number): void {\n if (k.length !== expected) {\n throw new NumericalBackendError(\n `integrateRK4: ODE system returned a state vector of length ${k.length}, expected ${expected}`,\n );\n }\n}\n\n/**\n * Integrate `system` from affine parameter `lambda0` to `lambda1` in\n * `steps` fixed RK4 steps, starting from state `y0`. Returns the final\n * state vector. Classical 4th-order Runge-Kutta — global error O(h⁴).\n *\n * @internal — cross-module/test use only; not part of the consumer surface.\n */\nexport function integrateRK4(\n system: ODESystem,\n y0: ReadonlyArray<number>,\n lambda0: number,\n lambda1: number,\n steps: number,\n): number[] {\n if (!Number.isInteger(steps) || steps <= 0) {\n throw new NumericalBackendError(`integrateRK4: step count must be a positive integer, got ${steps}`);\n }\n const h = (lambda1 - lambda0) / steps;\n const yStart = [...y0];\n const sol = solveODESystem(\n (lambda, y) => {\n const k = system(lambda, y);\n checkLength(k, yStart.length);\n return k;\n },\n yStart,\n [lambda0, lambda1],\n { dt: h },\n );\n return [...(sol.y[sol.y.length - 1] ?? yStart)];\n}\n"]}
1
+ {"version":3,"file":"null-ray-integrator.js","sourceRoot":"","sources":["../../src/numerical/null-ray-integrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOpD,SAAS,WAAW,CAAC,CAAwB,EAAE,QAAgB;IAC7D,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,qBAAqB,CAC7B,8DAA8D,CAAC,CAAC,MAAM,cAAc,QAAQ,EAAE,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAiB,EACjB,EAAyB,EACzB,OAAe,EACf,OAAe,EACf,KAAa;IAEb,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,qBAAqB,CAAC,4DAA4D,KAAK,EAAE,CAAC,CAAC;IACvG,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,aAAa,CAC1B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACZ,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5B,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC;IACX,CAAC,EACD,MAAM,EACN,OAAO,EACP,OAAO,EACP,KAAK,CACN,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC;AAC7C,CAAC","sourcesContent":["/**\n * Fixed-step classical RK4 integrator for affine-parameterized null\n * geodesics, and the one-step RK4 the atlas and case modules call. The\n * covariant-eikonal path (`src/numerical/covariant-eikonal.ts`) uses the\n * symplectic `integrateGeodesicGL4` instead. The fixed steps are\n * `rk4Trajectory` (`rk4-trajectory.ts`, MathTS `solveODESystem` with `dt`),\n * the one owner of the step count; this module returns its last state.\n * Operates on plain `number[]` state vectors, no TensorEngine dependency.\n *\n * @module numerical/null-ray-integrator\n */\nimport { NumericalBackendError } from './errors.js';\nimport { rk4Trajectory } from './rk4-trajectory.js';\n\n/** A first-order ODE system: dy/dλ = f(λ, y). `y` and the return are\n * state vectors of equal length.\n * v0.6.1: dropped export — was @internal-tagged with no external consumer. */\ntype ODESystem = (lambda: number, y: ReadonlyArray<number>) => number[];\n\nfunction checkLength(k: ReadonlyArray<number>, expected: number): void {\n if (k.length !== expected) {\n throw new NumericalBackendError(\n `integrateRK4: ODE system returned a state vector of length ${k.length}, expected ${expected}`,\n );\n }\n}\n\n/**\n * Integrate `system` from affine parameter `lambda0` to `lambda1` in\n * `steps` fixed RK4 steps, starting from state `y0`. Returns the final\n * state vector. Classical 4th-order Runge-Kutta — global error O(h⁴). It takes\n * exactly `steps` steps of (lambda1 − lambda0)/steps (`rk4Trajectory`).\n *\n * @internal — cross-module/test use only; not part of the consumer surface.\n */\nexport function integrateRK4(\n system: ODESystem,\n y0: ReadonlyArray<number>,\n lambda0: number,\n lambda1: number,\n steps: number,\n): number[] {\n if (!Number.isInteger(steps) || steps <= 0) {\n throw new NumericalBackendError(`integrateRK4: step count must be a positive integer, got ${steps}`);\n }\n const yStart = [...y0];\n const states = rk4Trajectory(\n (lambda, y) => {\n const k = system(lambda, y);\n checkLength(k, yStart.length);\n return k;\n },\n yStart,\n lambda0,\n lambda1,\n steps,\n );\n return states[states.length - 1] ?? yStart;\n}\n"]}
@@ -50,7 +50,7 @@
50
50
  *
51
51
  * @module numerical/painleve-gullstrand-metric
52
52
  */
53
- import { C_SI, G_SI } from '../core/constants.js';
53
+ import { schwarzschildRadius } from './schwarzschild.js';
54
54
  /**
55
55
  * Schwarzschild radius `r_s = 2 G M / c²` for a body of mass `M`.
56
56
  * Inlined here to avoid an out-of-rootDir import on the test
@@ -59,7 +59,7 @@ import { C_SI, G_SI } from '../core/constants.js';
59
59
  * @internal
60
60
  */
61
61
  function schwarzschildRs(M_kg) {
62
- return (2 * G_SI * M_kg) / (C_SI * C_SI);
62
+ return schwarzschildRadius(M_kg);
63
63
  }
64
64
  /**
65
65
  * Builds a Painlevé-Gullstrand metric function `g_μν(T, r, θ, φ)`
@@ -1 +1 @@
1
- {"version":3,"file":"painleve-gullstrand-metric.js","sourceRoot":"","sources":["../../src/numerical/painleve-gullstrand-metric.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Painlevé-Gullstrand (PG) metric for Schwarzschild spacetime —\n * regular at the event horizon.\n *\n * Per `docs/architecture/archive/v0.7-near-horizon-kretschmann-design-note.md`\n * (v0.7 follow-up to v0.6.0's deferred \"Near-horizon Kretschmann\"\n * item). Schwarzschild coordinates have a coordinate singularity at\n * `r = r_s` (the event horizon); `g_rr = 1/(1−r_s/r) → ∞`. The\n * Painlevé-Gullstrand coordinate system is regular at the horizon\n * (and everywhere outside the curvature singularity at `r=0`).\n *\n * Coordinate transform (closed-form, no implicit-function solve):\n *\n * T = t + 2√(r·r_s) + r_s·ln|(√r − √r_s)/(√r + √r_s)|\n *\n * In PG coordinates (T, r, θ, φ):\n *\n * ds² = -(1 − r_s/r) dT² + 2√(r_s/r) dT dr + dr² + r² dΩ²\n *\n * Matrix form:\n *\n * g_μν = [[-(1−r_s/r), √(r_s/r), 0, 0 ],\n * [ √(r_s/r), 1, 0, 0 ],\n * [ 0, 0, r², 0 ],\n * [ 0, 0, 0, r² sin²θ ]]\n *\n * Inverse (closed-form via 2x2 block inverse on the (T,r) block,\n * det = -1):\n *\n * g^μν = [[-1, √(r_s/r), 0, 0 ],\n * [ √(r_s/r), (1−r_s/r), 0, 0 ],\n * [ 0, 0, 1/r², 0 ],\n * [ 0, 0, 0, 1/(r² sin²θ)]]\n *\n * Verification at the horizon:\n *\n * r → r_s: g_TT → 0, g_Tr → 1, g_rr → 1 (all finite)\n * g^rr → 0, g^Tr → 1, g^TT → -1 (all finite)\n *\n * Compare to Schwarzschild where g_rr → ∞. The Kretschmann\n * scalar K = R_μνρσ R^μνρσ is computed via the existing\n * `numerical/kretschmann.ts` (coordinate-agnostic — takes raw\n * arrays) fed by Riemann assembled from these closed-form metric\n * functions via the existing FD pipeline. At r=r_s the analytic\n * value `K = 48 G²M²/(c⁴ r_s⁶) = 12/r_s⁴` (in c=G=1 units) is\n * recovered numerically without coordinate-singularity blowup.\n *\n * Reference: MTW §31.4 (\"Lemaître coordinates\" + the\n * Painlevé-Gullstrand variant); Carroll §5.7.\n *\n * @module numerical/painleve-gullstrand-metric\n */\n\nimport { C_SI, G_SI } from '../core/constants.js';\nimport type { MetricFnFlat } from './curvature-lowering-helpers.js';\n\n/**\n * Schwarzschild radius `r_s = 2 G M / c²` for a body of mass `M`.\n * Inlined here to avoid an out-of-rootDir import on the test\n * fixture's `schwarzschildRs` helper. Same formula.\n *\n * @internal\n */\nfunction schwarzschildRs(M_kg: number): number {\n return (2 * G_SI * M_kg) / (C_SI * C_SI);\n}\n\n/**\n * Builds a Painlevé-Gullstrand metric function `g_μν(T, r, θ, φ)`\n * for a Schwarzschild black hole of mass `M_kg`.\n *\n * The returned function maps a 4-tuple coordinate point to the\n * 4×4 lower-lower metric as a row-major `Float64Array(16)` —\n * `flat[mu*4 + nu] = g_{μν}` (v0.9.0 O-6 migration, mirroring the\n * v0.6.0 BR-2 christoffelFn convention). Closed-form; no FD;\n * regular at r=r_s.\n *\n * BREAKING (v0.9.0) for subpath-import consumers: previously\n * returned `number[][]`.\n *\n * @public\n */\nexport function painleveGullstrandGFn(M_kg: number): MetricFnFlat {\n const r_s = schwarzschildRs(M_kg);\n return function pgG(x: ReadonlyArray<number>): Float64Array {\n const r = x[1];\n const theta = x[2];\n if (!(r > 0)) {\n throw new RangeError(`painleveGullstrandGFn: r must be > 0, got ${r}`);\n }\n const rho = r_s / r;\n const sqrtRho = Math.sqrt(rho);\n const sinTheta = Math.sin(theta);\n const out = new Float64Array(16);\n out[0 * 4 + 0] = -(1 - rho);\n out[0 * 4 + 1] = sqrtRho;\n out[1 * 4 + 0] = sqrtRho;\n out[1 * 4 + 1] = 1;\n out[2 * 4 + 2] = r * r;\n out[3 * 4 + 3] = r * r * sinTheta * sinTheta;\n return out;\n };\n}\n\n/**\n * Builds a Painlevé-Gullstrand inverse-metric function `g^μν(T, r,\n * θ, φ)`. Closed-form (2×2 block inverse on the (T, r) block,\n * det = -1; angular block is trivially diagonal).\n *\n * Returns a row-major `Float64Array(16)` — `flat[mu*4 + nu] = g^{μν}`\n * (v0.9.0 O-6 migration). At r=r_s, g^rr=0 (the horizon's\n * coordinate-regularity signature in PG: NO divergence). At r→∞,\n * g^rr → 1 (asymptotic flatness).\n *\n * BREAKING (v0.9.0) for subpath-import consumers: previously\n * returned `number[][]`.\n *\n * @public\n */\nexport function painleveGullstrandGInverseFn(M_kg: number): MetricFnFlat {\n const r_s = schwarzschildRs(M_kg);\n return function pgGInv(x: ReadonlyArray<number>): Float64Array {\n const r = x[1];\n const theta = x[2];\n if (!(r > 0)) {\n throw new RangeError(`painleveGullstrandGInverseFn: r must be > 0, got ${r}`);\n }\n const rho = r_s / r;\n const sqrtRho = Math.sqrt(rho);\n const sinTheta = Math.sin(theta);\n const out = new Float64Array(16);\n out[0 * 4 + 0] = -1;\n out[0 * 4 + 1] = sqrtRho;\n out[1 * 4 + 0] = sqrtRho;\n out[1 * 4 + 1] = 1 - rho;\n out[2 * 4 + 2] = 1 / (r * r);\n out[3 * 4 + 3] = 1 / (r * r * sinTheta * sinTheta);\n return out;\n };\n}\n"]}
1
+ {"version":3,"file":"painleve-gullstrand-metric.js","sourceRoot":"","sources":["../../src/numerical/painleve-gullstrand-metric.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Painlevé-Gullstrand (PG) metric for Schwarzschild spacetime —\n * regular at the event horizon.\n *\n * Per `docs/architecture/archive/v0.7-near-horizon-kretschmann-design-note.md`\n * (v0.7 follow-up to v0.6.0's deferred \"Near-horizon Kretschmann\"\n * item). Schwarzschild coordinates have a coordinate singularity at\n * `r = r_s` (the event horizon); `g_rr = 1/(1−r_s/r) → ∞`. The\n * Painlevé-Gullstrand coordinate system is regular at the horizon\n * (and everywhere outside the curvature singularity at `r=0`).\n *\n * Coordinate transform (closed-form, no implicit-function solve):\n *\n * T = t + 2√(r·r_s) + r_s·ln|(√r − √r_s)/(√r + √r_s)|\n *\n * In PG coordinates (T, r, θ, φ):\n *\n * ds² = -(1 − r_s/r) dT² + 2√(r_s/r) dT dr + dr² + r² dΩ²\n *\n * Matrix form:\n *\n * g_μν = [[-(1−r_s/r), √(r_s/r), 0, 0 ],\n * [ √(r_s/r), 1, 0, 0 ],\n * [ 0, 0, r², 0 ],\n * [ 0, 0, 0, r² sin²θ ]]\n *\n * Inverse (closed-form via 2x2 block inverse on the (T,r) block,\n * det = -1):\n *\n * g^μν = [[-1, √(r_s/r), 0, 0 ],\n * [ √(r_s/r), (1−r_s/r), 0, 0 ],\n * [ 0, 0, 1/r², 0 ],\n * [ 0, 0, 0, 1/(r² sin²θ)]]\n *\n * Verification at the horizon:\n *\n * r → r_s: g_TT → 0, g_Tr → 1, g_rr → 1 (all finite)\n * g^rr → 0, g^Tr → 1, g^TT → -1 (all finite)\n *\n * Compare to Schwarzschild where g_rr → ∞. The Kretschmann\n * scalar K = R_μνρσ R^μνρσ is computed via the existing\n * `numerical/kretschmann.ts` (coordinate-agnostic — takes raw\n * arrays) fed by Riemann assembled from these closed-form metric\n * functions via the existing FD pipeline. At r=r_s the analytic\n * value `K = 48 G²M²/(c⁴ r_s⁶) = 12/r_s⁴` (in c=G=1 units) is\n * recovered numerically without coordinate-singularity blowup.\n *\n * Reference: MTW §31.4 (\"Lemaître coordinates\" + the\n * Painlevé-Gullstrand variant); Carroll §5.7.\n *\n * @module numerical/painleve-gullstrand-metric\n */\n\nimport { schwarzschildRadius } from './schwarzschild.js';\nimport type { MetricFnFlat } from './curvature-lowering-helpers.js';\n\n/**\n * Schwarzschild radius `r_s = 2 G M / c²` for a body of mass `M`.\n * Inlined here to avoid an out-of-rootDir import on the test\n * fixture's `schwarzschildRs` helper. Same formula.\n *\n * @internal\n */\nfunction schwarzschildRs(M_kg: number): number {\n return schwarzschildRadius(M_kg);\n}\n\n/**\n * Builds a Painlevé-Gullstrand metric function `g_μν(T, r, θ, φ)`\n * for a Schwarzschild black hole of mass `M_kg`.\n *\n * The returned function maps a 4-tuple coordinate point to the\n * 4×4 lower-lower metric as a row-major `Float64Array(16)` —\n * `flat[mu*4 + nu] = g_{μν}` (v0.9.0 O-6 migration, mirroring the\n * v0.6.0 BR-2 christoffelFn convention). Closed-form; no FD;\n * regular at r=r_s.\n *\n * BREAKING (v0.9.0) for subpath-import consumers: previously\n * returned `number[][]`.\n *\n * @public\n */\nexport function painleveGullstrandGFn(M_kg: number): MetricFnFlat {\n const r_s = schwarzschildRs(M_kg);\n return function pgG(x: ReadonlyArray<number>): Float64Array {\n const r = x[1];\n const theta = x[2];\n if (!(r > 0)) {\n throw new RangeError(`painleveGullstrandGFn: r must be > 0, got ${r}`);\n }\n const rho = r_s / r;\n const sqrtRho = Math.sqrt(rho);\n const sinTheta = Math.sin(theta);\n const out = new Float64Array(16);\n out[0 * 4 + 0] = -(1 - rho);\n out[0 * 4 + 1] = sqrtRho;\n out[1 * 4 + 0] = sqrtRho;\n out[1 * 4 + 1] = 1;\n out[2 * 4 + 2] = r * r;\n out[3 * 4 + 3] = r * r * sinTheta * sinTheta;\n return out;\n };\n}\n\n/**\n * Builds a Painlevé-Gullstrand inverse-metric function `g^μν(T, r,\n * θ, φ)`. Closed-form (2×2 block inverse on the (T, r) block,\n * det = -1; angular block is trivially diagonal).\n *\n * Returns a row-major `Float64Array(16)` — `flat[mu*4 + nu] = g^{μν}`\n * (v0.9.0 O-6 migration). At r=r_s, g^rr=0 (the horizon's\n * coordinate-regularity signature in PG: NO divergence). At r→∞,\n * g^rr → 1 (asymptotic flatness).\n *\n * BREAKING (v0.9.0) for subpath-import consumers: previously\n * returned `number[][]`.\n *\n * @public\n */\nexport function painleveGullstrandGInverseFn(M_kg: number): MetricFnFlat {\n const r_s = schwarzschildRs(M_kg);\n return function pgGInv(x: ReadonlyArray<number>): Float64Array {\n const r = x[1];\n const theta = x[2];\n if (!(r > 0)) {\n throw new RangeError(`painleveGullstrandGInverseFn: r must be > 0, got ${r}`);\n }\n const rho = r_s / r;\n const sqrtRho = Math.sqrt(rho);\n const sinTheta = Math.sin(theta);\n const out = new Float64Array(16);\n out[0 * 4 + 0] = -1;\n out[0 * 4 + 1] = sqrtRho;\n out[1 * 4 + 0] = sqrtRho;\n out[1 * 4 + 1] = 1 - rho;\n out[2 * 4 + 2] = 1 / (r * r);\n out[3 * 4 + 3] = 1 / (r * r * sinTheta * sinTheta);\n return out;\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"pderiv.d.ts","sourceRoot":"","sources":["../../src/numerical/pderiv.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiClE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,UAAU,aAAa;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,WAAW,EAClD,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,aAAa,GACtB,WAAW,CAgEb;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAC5C,WAAW,CAWb;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAClD,WAAW,CAYb"}
1
+ {"version":3,"file":"pderiv.d.ts","sourceRoot":"","sources":["../../src/numerical/pderiv.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BlE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,UAAU,aAAa;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,WAAW,EAClD,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,aAAa,GACtB,WAAW,CAgEb;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAC5C,WAAW,CAWb;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAClD,WAAW,CAYb"}
@@ -1,5 +1,6 @@
1
1
  import { NumericalBackendError } from './errors.js';
2
2
  import { flattenNA } from './connection-lowering-helpers.js';
3
+ import { rowMajorStrides } from './strides.js';
3
4
  /**
4
5
  * Centered finite-difference of a GridField along `axis`. Returns a flat
5
6
  * number[] of the same total size as the grid. O(h²) interior stencil;
@@ -19,12 +20,7 @@ export function pderivGrid(grid, axis) {
19
20
  }
20
21
  const flat = flattenNA(grid.data);
21
22
  const shape = grid.shape;
22
- const strides = new Array(shape.length);
23
- let acc = 1;
24
- for (let k = shape.length - 1; k >= 0; k--) {
25
- strides[k] = acc;
26
- acc *= shape[k];
27
- }
23
+ const strides = rowMajorStrides(shape);
28
24
  const out = new Array(flat.length).fill(0);
29
25
  const n = shape[axis];
30
26
  const step = strides[axis];
@@ -1 +1 @@
1
- {"version":3,"file":"pderiv.js","sourceRoot":"","sources":["../../src/numerical/pderiv.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Numerical partial derivative — two-way dispatch (v0.3.5-Design.md §6).\n * 'grid' — centered finite-difference over a GridField.\n * 'numerical-fn' — centered finite-difference over a caller-supplied fn.\n * 'symbolic' — no CAS in v0.3.5; consumes an explicit pre-supplied\n * derivative from NumericalInputs.derivatives.\n *\n * @module numerical/pderiv\n */\nimport type { GridField } from './grid-field.js';\nimport type { NestedArray } from './types.js';\nimport { NumericalBackendError } from './errors.js';\nimport { flattenNA } from './connection-lowering-helpers.js';\n\n/**\n * Centered finite-difference of a GridField along `axis`. Returns a flat\n * number[] of the same total size as the grid. O(h²) interior stencil;\n * edges follow `grid.boundary`:\n * - 'clamp' — one-sided (forward/backward) difference at the edge.\n * - 'periodic' — wraps to the opposite edge.\n *\n * @internal — consumed by the lowering pass; not part of the consumer surface.\n */\nexport function pderivGrid(grid: GridField, axis: number): number[] {\n if (axis < 0 || axis >= grid.shape.length) {\n throw new NumericalBackendError(`pderivGrid: axis ${axis} out of range for shape [${grid.shape}]`);\n }\n const h = grid.spacing[axis];\n if (!(h > 0)) {\n throw new NumericalBackendError(`pderivGrid: non-positive spacing ${h} on axis ${axis}`);\n }\n const flat = flattenNA(grid.data);\n const shape = grid.shape;\n const strides: number[] = new Array(shape.length);\n let acc = 1;\n for (let k = shape.length - 1; k >= 0; k--) { strides[k] = acc; acc *= shape[k]; }\n const out = new Array<number>(flat.length).fill(0);\n const n = shape[axis];\n const step = strides[axis];\n\n // Walk every multi-index; compute the axis position from the flat index.\n for (let f = 0; f < flat.length; f++) {\n const pos = Math.floor(f / step) % n;\n if (pos > 0 && pos < n - 1) {\n out[f] = (flat[f + step] - flat[f - step]) / (2 * h);\n } else if (grid.boundary === 'periodic') {\n const next = pos === n - 1 ? f - (n - 1) * step : f + step;\n const prev = pos === 0 ? f + (n - 1) * step : f - step;\n out[f] = (flat[next] - flat[prev]) / (2 * h);\n } else { // 'clamp' — one-sided difference at the edge\n out[f] = pos === 0\n ? (flat[f + step] - flat[f]) / h\n : (flat[f] - flat[f - step]) / h;\n }\n }\n return out;\n}\n\n/**\n * Options for {@link pderivNumericalFn}.\n *\n * - `order` — stencil order. Default **4** as of v0.6.0 (was 2 in v0.5.x,\n * Decision #7). `4` uses the 4-point centered\n * `(−f(x+2h) + 8 f(x+h) − 8 f(x−h) + f(x−2h)) / (12 h)`\n * form with adaptive `h = 1e-4·max(|x|,1)`. 4th-order has ~2× FD\n * evaluations vs 2nd-order but ~10⁴× lower truncation error; preferred\n * default for curvature/Schwarzschild-scale computations where\n * c²·g_tt ~ 6e16 causes 2nd-order cancellation noise.\n * `2` uses the classic centered `(f(x+h) − f(x−h)) / (2h)` form with\n * adaptive `h = 1e-6·max(|x|,1)`. Use `{ order: 2 }` explicitly to\n * preserve v0.5.x 2nd-order semantics.\n * v0.5.1 PD-7 introduced the parameter; v0.6.0 Task 2.12 flipped the default.\n *\n * - `h` — optional explicit step override. Used by\n * `curvature-lowering-helpers.ts` for its inner ∂g sampler where the\n * c²-scaled g_tt cancellation noise needs a larger-than-default step\n * (`1e-3·max(|x|,1)`) to balance truncation vs round-off. If supplied,\n * the adaptive default is bypassed entirely.\n */\n// v0.6.1: dropped export — internal-only options shape for pderivNumericalFn.\ninterface PderivOptions {\n readonly order?: 2 | 4;\n readonly h?: number;\n}\n\n/**\n * Centered finite-difference of a caller-supplied scalar (or tensor-valued)\n * field with respect to coordinate `axis`.\n *\n * - 4th-order (default as of v0.6.0): step h = 1e-4 · max(|x|, 1).\n * ~2× FD evaluations vs 2nd-order; ~10⁴× lower truncation error.\n * Preferred for curvature/Schwarzschild-scale computations.\n * - 2nd-order (`options.order === 2`): step h = 1e-6 · max(|x|, 1)\n * (v0.3.5-Design.md §13 Q3). Use `{ order: 2 }` to preserve v0.5.x semantics.\n *\n * @internal — consumed by the lowering pass; not part of the consumer surface.\n */\nexport function pderivNumericalFn(\n fn: (coords: ReadonlyArray<number>) => NestedArray,\n coords: ReadonlyArray<number>,\n axis: number,\n options?: PderivOptions,\n): NestedArray {\n if (axis < 0 || axis >= coords.length) {\n throw new NumericalBackendError(`pderivNumericalFn: axis ${axis} out of range`);\n }\n const order = options?.order ?? 4;\n if (order !== 2 && order !== 4) {\n throw new NumericalBackendError(\n `pderivNumericalFn: unsupported order ${order} — only 2 or 4 are supported`,\n );\n }\n const x = coords[axis];\n const defaultH = (order === 4 ? 1e-4 : 1e-6) * Math.max(Math.abs(x), 1);\n const h = options?.h ?? defaultH;\n if (!(h > 0) || !Number.isFinite(h)) {\n throw new NumericalBackendError(\n `pderivNumericalFn: non-positive or non-finite step h=${h}`,\n );\n }\n\n if (order === 2) {\n const plus = [...coords]; plus[axis] = x + h;\n const minus = [...coords]; minus[axis] = x - h;\n const fp = flattenNA(fn(plus));\n const fm = flattenNA(fn(minus));\n if (fp.length !== fm.length) {\n throw new NumericalBackendError('pderivNumericalFn: field returned inconsistent shapes');\n }\n const len = fp.length;\n const d = new Array(len);\n const inv2h = 1 / (2 * h);\n for (let i = 0; i < len; i++) {\n // A component that is the same number at every stencil point does not\n // move: its derivative is exactly 0, not the stencil's roundoff over h.\n d[i] = fp[i] === fm[i] ? 0 : (fp[i] - fm[i]) * inv2h;\n }\n return d.length === 1 ? d[0] : d;\n }\n\n // order === 4: f'(x) ≈ (−f(x+2h) + 8 f(x+h) − 8 f(x−h) + f(x−2h)) / (12 h)\n const p1 = [...coords]; p1[axis] = x + h;\n const m1 = [...coords]; m1[axis] = x - h;\n const p2 = [...coords]; p2[axis] = x + 2 * h;\n const m2 = [...coords]; m2[axis] = x - 2 * h;\n const fp1 = flattenNA(fn(p1));\n const fm1 = flattenNA(fn(m1));\n const fp2 = flattenNA(fn(p2));\n const fm2 = flattenNA(fn(m2));\n if (\n fp1.length !== fm1.length || fp1.length !== fp2.length || fp1.length !== fm2.length\n ) {\n throw new NumericalBackendError('pderivNumericalFn: field returned inconsistent shapes');\n }\n const inv12h = 1 / (12 * h);\n const len = fp1.length;\n const d = new Array(len);\n for (let i = 0; i < len; i++) {\n // A component that is the same number at every stencil point does not\n // move: its derivative is exactly 0. The stencil cancels a large constant\n // (g_tt = −c²) only up to the roundoff of 8·f, and that roundoff over h\n // is a fake derivative of order 10⁴.\n const still = fp1[i] === fm1[i] && fp1[i] === fp2[i] && fp1[i] === fm2[i];\n d[i] = still ? 0 : (-fp2[i] + 8 * fp1[i] - 8 * fm1[i] + fm2[i]) * inv12h;\n }\n return d.length === 1 ? d[0] : d;\n}\n\n/**\n * 'symbolic' numericalForm path: v0.3.5 has no CAS, so the caller supplies\n * the derivative explicitly, keyed `${symbolName}/${coordLabel}`.\n *\n * @internal — consumed by the lowering pass; not part of the consumer surface.\n */\nexport function pderivSymbolic(\n symbolName: string,\n coordLabel: string,\n derivatives: ReadonlyMap<string, NestedArray>,\n): NestedArray {\n const key = `${symbolName}/${coordLabel}`;\n const d = derivatives.get(key);\n if (d === undefined) {\n throw new NumericalBackendError(\n `pderivSymbolic: no explicit derivative supplied for \"${key}\" — `\n + `a 'symbolic' tensor-symbol under a partial-derivative requires `\n + `inputs.derivatives to contain its pre-computed components (v0.3.5 has no CAS)`,\n );\n }\n return d;\n}\n\n/**\n * 'supplied' derivativeStrategy path: v0.4.0 metric derivative looked up\n * from explicit caller-supplied components. Keyed `${metricName}/${coordLabel}`.\n * Mirror of `pderivSymbolic` for the metric-tensor lowering path.\n * Throws NumericalBackendError with a clear message when absent.\n */\nexport function metricDerivSupplied(\n metricName: string,\n coordLabel: string,\n metricDerivatives: ReadonlyMap<string, NestedArray>,\n): NestedArray {\n const key = `${metricName}/${coordLabel}`;\n const d = metricDerivatives.get(key);\n if (d === undefined) {\n throw new NumericalBackendError(\n `metricDerivSupplied: no metric derivative supplied for \"${key}\" — `\n + `a metric-tensor with derivativeStrategy='supplied' under a `\n + `christoffel/covariant-derivative requires inputs.metricDerivatives `\n + `to contain its pre-computed ∂g components`,\n );\n }\n return d;\n}\n"]}
1
+ {"version":3,"file":"pderiv.js","sourceRoot":"","sources":["../../src/numerical/pderiv.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Numerical partial derivative — two-way dispatch (v0.3.5-Design.md §6).\n * 'grid' — centered finite-difference over a GridField.\n * 'numerical-fn' — centered finite-difference over a caller-supplied fn.\n * 'symbolic' — no CAS in v0.3.5; consumes an explicit pre-supplied\n * derivative from NumericalInputs.derivatives.\n *\n * @module numerical/pderiv\n */\nimport type { GridField } from './grid-field.js';\nimport type { NestedArray } from './types.js';\nimport { NumericalBackendError } from './errors.js';\nimport { flattenNA } from './connection-lowering-helpers.js';\nimport { rowMajorStrides } from './strides.js';\n\n/**\n * Centered finite-difference of a GridField along `axis`. Returns a flat\n * number[] of the same total size as the grid. O(h²) interior stencil;\n * edges follow `grid.boundary`:\n * - 'clamp' — one-sided (forward/backward) difference at the edge.\n * - 'periodic' — wraps to the opposite edge.\n *\n * @internal — consumed by the lowering pass; not part of the consumer surface.\n */\nexport function pderivGrid(grid: GridField, axis: number): number[] {\n if (axis < 0 || axis >= grid.shape.length) {\n throw new NumericalBackendError(`pderivGrid: axis ${axis} out of range for shape [${grid.shape}]`);\n }\n const h = grid.spacing[axis];\n if (!(h > 0)) {\n throw new NumericalBackendError(`pderivGrid: non-positive spacing ${h} on axis ${axis}`);\n }\n const flat = flattenNA(grid.data);\n const shape = grid.shape;\n const strides = rowMajorStrides(shape);\n const out = new Array<number>(flat.length).fill(0);\n const n = shape[axis];\n const step = strides[axis];\n\n // Walk every multi-index; compute the axis position from the flat index.\n for (let f = 0; f < flat.length; f++) {\n const pos = Math.floor(f / step) % n;\n if (pos > 0 && pos < n - 1) {\n out[f] = (flat[f + step] - flat[f - step]) / (2 * h);\n } else if (grid.boundary === 'periodic') {\n const next = pos === n - 1 ? f - (n - 1) * step : f + step;\n const prev = pos === 0 ? f + (n - 1) * step : f - step;\n out[f] = (flat[next] - flat[prev]) / (2 * h);\n } else { // 'clamp' — one-sided difference at the edge\n out[f] = pos === 0\n ? (flat[f + step] - flat[f]) / h\n : (flat[f] - flat[f - step]) / h;\n }\n }\n return out;\n}\n\n/**\n * Options for {@link pderivNumericalFn}.\n *\n * - `order` — stencil order. Default **4** as of v0.6.0 (was 2 in v0.5.x,\n * Decision #7). `4` uses the 4-point centered\n * `(−f(x+2h) + 8 f(x+h) − 8 f(x−h) + f(x−2h)) / (12 h)`\n * form with adaptive `h = 1e-4·max(|x|,1)`. 4th-order has ~2× FD\n * evaluations vs 2nd-order but ~10⁴× lower truncation error; preferred\n * default for curvature/Schwarzschild-scale computations where\n * c²·g_tt ~ 6e16 causes 2nd-order cancellation noise.\n * `2` uses the classic centered `(f(x+h) − f(x−h)) / (2h)` form with\n * adaptive `h = 1e-6·max(|x|,1)`. Use `{ order: 2 }` explicitly to\n * preserve v0.5.x 2nd-order semantics.\n * v0.5.1 PD-7 introduced the parameter; v0.6.0 Task 2.12 flipped the default.\n *\n * - `h` — optional explicit step override. Used by\n * `curvature-lowering-helpers.ts` for its inner ∂g sampler where the\n * c²-scaled g_tt cancellation noise needs a larger-than-default step\n * (`1e-3·max(|x|,1)`) to balance truncation vs round-off. If supplied,\n * the adaptive default is bypassed entirely.\n */\n// v0.6.1: dropped export — internal-only options shape for pderivNumericalFn.\ninterface PderivOptions {\n readonly order?: 2 | 4;\n readonly h?: number;\n}\n\n/**\n * Centered finite-difference of a caller-supplied scalar (or tensor-valued)\n * field with respect to coordinate `axis`.\n *\n * - 4th-order (default as of v0.6.0): step h = 1e-4 · max(|x|, 1).\n * ~2× FD evaluations vs 2nd-order; ~10⁴× lower truncation error.\n * Preferred for curvature/Schwarzschild-scale computations.\n * - 2nd-order (`options.order === 2`): step h = 1e-6 · max(|x|, 1)\n * (v0.3.5-Design.md §13 Q3). Use `{ order: 2 }` to preserve v0.5.x semantics.\n *\n * @internal — consumed by the lowering pass; not part of the consumer surface.\n */\nexport function pderivNumericalFn(\n fn: (coords: ReadonlyArray<number>) => NestedArray,\n coords: ReadonlyArray<number>,\n axis: number,\n options?: PderivOptions,\n): NestedArray {\n if (axis < 0 || axis >= coords.length) {\n throw new NumericalBackendError(`pderivNumericalFn: axis ${axis} out of range`);\n }\n const order = options?.order ?? 4;\n if (order !== 2 && order !== 4) {\n throw new NumericalBackendError(\n `pderivNumericalFn: unsupported order ${order} — only 2 or 4 are supported`,\n );\n }\n const x = coords[axis];\n const defaultH = (order === 4 ? 1e-4 : 1e-6) * Math.max(Math.abs(x), 1);\n const h = options?.h ?? defaultH;\n if (!(h > 0) || !Number.isFinite(h)) {\n throw new NumericalBackendError(\n `pderivNumericalFn: non-positive or non-finite step h=${h}`,\n );\n }\n\n if (order === 2) {\n const plus = [...coords]; plus[axis] = x + h;\n const minus = [...coords]; minus[axis] = x - h;\n const fp = flattenNA(fn(plus));\n const fm = flattenNA(fn(minus));\n if (fp.length !== fm.length) {\n throw new NumericalBackendError('pderivNumericalFn: field returned inconsistent shapes');\n }\n const len = fp.length;\n const d = new Array(len);\n const inv2h = 1 / (2 * h);\n for (let i = 0; i < len; i++) {\n // A component that is the same number at every stencil point does not\n // move: its derivative is exactly 0, not the stencil's roundoff over h.\n d[i] = fp[i] === fm[i] ? 0 : (fp[i] - fm[i]) * inv2h;\n }\n return d.length === 1 ? d[0] : d;\n }\n\n // order === 4: f'(x) ≈ (−f(x+2h) + 8 f(x+h) − 8 f(x−h) + f(x−2h)) / (12 h)\n const p1 = [...coords]; p1[axis] = x + h;\n const m1 = [...coords]; m1[axis] = x - h;\n const p2 = [...coords]; p2[axis] = x + 2 * h;\n const m2 = [...coords]; m2[axis] = x - 2 * h;\n const fp1 = flattenNA(fn(p1));\n const fm1 = flattenNA(fn(m1));\n const fp2 = flattenNA(fn(p2));\n const fm2 = flattenNA(fn(m2));\n if (\n fp1.length !== fm1.length || fp1.length !== fp2.length || fp1.length !== fm2.length\n ) {\n throw new NumericalBackendError('pderivNumericalFn: field returned inconsistent shapes');\n }\n const inv12h = 1 / (12 * h);\n const len = fp1.length;\n const d = new Array(len);\n for (let i = 0; i < len; i++) {\n // A component that is the same number at every stencil point does not\n // move: its derivative is exactly 0. The stencil cancels a large constant\n // (g_tt = −c²) only up to the roundoff of 8·f, and that roundoff over h\n // is a fake derivative of order 10⁴.\n const still = fp1[i] === fm1[i] && fp1[i] === fp2[i] && fp1[i] === fm2[i];\n d[i] = still ? 0 : (-fp2[i] + 8 * fp1[i] - 8 * fm1[i] + fm2[i]) * inv12h;\n }\n return d.length === 1 ? d[0] : d;\n}\n\n/**\n * 'symbolic' numericalForm path: v0.3.5 has no CAS, so the caller supplies\n * the derivative explicitly, keyed `${symbolName}/${coordLabel}`.\n *\n * @internal — consumed by the lowering pass; not part of the consumer surface.\n */\nexport function pderivSymbolic(\n symbolName: string,\n coordLabel: string,\n derivatives: ReadonlyMap<string, NestedArray>,\n): NestedArray {\n const key = `${symbolName}/${coordLabel}`;\n const d = derivatives.get(key);\n if (d === undefined) {\n throw new NumericalBackendError(\n `pderivSymbolic: no explicit derivative supplied for \"${key}\" — `\n + `a 'symbolic' tensor-symbol under a partial-derivative requires `\n + `inputs.derivatives to contain its pre-computed components (v0.3.5 has no CAS)`,\n );\n }\n return d;\n}\n\n/**\n * 'supplied' derivativeStrategy path: v0.4.0 metric derivative looked up\n * from explicit caller-supplied components. Keyed `${metricName}/${coordLabel}`.\n * Mirror of `pderivSymbolic` for the metric-tensor lowering path.\n * Throws NumericalBackendError with a clear message when absent.\n */\nexport function metricDerivSupplied(\n metricName: string,\n coordLabel: string,\n metricDerivatives: ReadonlyMap<string, NestedArray>,\n): NestedArray {\n const key = `${metricName}/${coordLabel}`;\n const d = metricDerivatives.get(key);\n if (d === undefined) {\n throw new NumericalBackendError(\n `metricDerivSupplied: no metric derivative supplied for \"${key}\" — `\n + `a metric-tensor with derivativeStrategy='supplied' under a `\n + `christoffel/covariant-derivative requires inputs.metricDerivatives `\n + `to contain its pre-computed ∂g components`,\n );\n }\n return d;\n}\n"]}
@@ -1,39 +1,3 @@
1
- /**
2
- * Bisection perihelion finder via cubic-Hermite interpolation on cached
3
- * GL4 snapshots (v0.5.0 Task 4, Phase 1b).
4
- *
5
- * Algorithm (Design §3 Task 1b):
6
- * 1. Walk snapshots, extract `dr/dτ_i = g^{rν}(x_i) · p_{i,ν}` at each
7
- * snapshot. Index `r` is the radial coordinate slot (index 1 by
8
- * convention in (t, r, θ, φ)).
9
- * 2. Locate consecutive indices `(i, i+1)` where `dr/dτ` sign-changes
10
- * from `−` to `+` — that is the perihelion (inner radial turning
11
- * point). Sign-change `+ → −` is apoapsis and is intentionally
12
- * skipped.
13
- * 3. **M3 bracket-width check:** if `|τ_{i+1} − τ_i| < 2 · h_snap`
14
- * where `h_snap` is the median Δτ across all snapshots, emit a
15
- * non-throwing `PerihelionBracketWidthWarning` via
16
- * `process.emitWarning`. This indicates the GL4 step is too coarse
17
- * to resolve the turning point — the caller should re-integrate
18
- * with finer steps.
19
- * 4. Fit a **cubic Hermite polynomial** through `(τ_i, dr/dτ_i)` and
20
- * `(τ_{i+1}, dr/dτ_{i+1})`, with endpoint derivatives estimated
21
- * from neighboring snapshots (4 values total: f and f' at both
22
- * endpoints). Find an analytic root of the cubic on [τ_i, τ_{i+1}].
23
- * 5. If `|P(τ_root)| > tauTolerance`, refine with **bisection on the
24
- * polynomial** (not re-integration — Adam+Eve I6/F11 — that would
25
- * cost a full GL4 sweep per bisection step, which defeats the
26
- * cached-snapshot approach). Precision floor: 1e-9 × T_orbit
27
- * (Adam+Eve I1 — 1e-12 needs ~40 cubic bisections and is wasted
28
- * effort given the integrator's per-step error is already > 1e-12).
29
- * 6. Return `{ tau, x, phi }` where `x` is the cubic-Hermite-interpolated
30
- * 4-coordinate at the root and `phi = x[3]`.
31
- *
32
- * **Throws** `Error("no perihelion bracket")` if no `−→+` sign-change is
33
- * found in the snapshot range.
34
- *
35
- * @module numerical/perihelion-finder
36
- */
37
1
  /**
38
2
  * Result of `findPerihelion`: the τ at the radial turning point, the
39
3
  * interpolated 4-coordinate, and the orbital phase `phi = x[3]`.
@@ -1 +1 @@
1
- {"version":3,"file":"perihelion-finder.d.ts","sourceRoot":"","sources":["../../src/numerical/perihelion-finder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;wEACoE;IACpE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAC/B,CAAC,CAAC;IACH;;4DAEwD;IACxD,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,YAAY,CAAC;IAC5D;;iEAE6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;qCACiC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAoJD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,gBAAgB,CAwG/E"}
1
+ {"version":3,"file":"perihelion-finder.d.ts","sourceRoot":"","sources":["../../src/numerical/perihelion-finder.ts"],"names":[],"mappings":"AA0CA;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;wEACoE;IACpE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAC/B,CAAC,CAAC;IACH;;4DAEwD;IACxD,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,YAAY,CAAC;IAC5D;;iEAE6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;qCACiC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAkGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,gBAAgB,CAwG/E"}
@@ -20,11 +20,14 @@
20
20
  * `(τ_{i+1}, dr/dτ_{i+1})`, with endpoint derivatives estimated
21
21
  * from neighboring snapshots (4 values total: f and f' at both
22
22
  * endpoints). Find an analytic root of the cubic on [τ_i, τ_{i+1}].
23
- * 5. If `|P(τ_root)| > tauTolerance`, refine with **bisection on the
24
- * polynomial** (not re-integration — Adam+Eve I6/F11 — that would
25
- * cost a full GL4 sweep per bisection step, which defeats the
26
- * cached-snapshot approach). Precision floor: 1e-9 × T_orbit
27
- * (Adam+Eve I1 — 1e-12 needs ~40 cubic bisections and is wasted
23
+ * 5. If `|P(τ_root)| > tauTolerance`, refine with **Brent's method on the
24
+ * polynomial** (MathTS `findRoot`, not re-integration — Adam+Eve
25
+ * I6/F11 — that would cost a full GL4 sweep per step, which defeats
26
+ * the cached-snapshot approach). `tauTolerance` is a RESIDUAL tolerance
27
+ * in the units of dr/dτ, so the search is run with `xtol: 0`
28
+ * (`@danielsimonjr/mathts-functions` ≥ 0.68.3): the solver stops on
29
+ * `|P| ≤ tauTolerance` alone, never on the bracket width in `s`.
30
+ * Precision floor: 1e-9 × T_orbit (Adam+Eve I1 — 1e-12 is wasted
28
31
  * effort given the integrator's per-step error is already > 1e-12).
29
32
  * 6. Return `{ tau, x, phi }` where `x` is the cubic-Hermite-interpolated
30
33
  * 4-coordinate at the root and `phi = x[3]`.
@@ -34,6 +37,8 @@
34
37
  *
35
38
  * @module numerical/perihelion-finder
36
39
  */
40
+ import { findRoot, hermiteInterp, median } from '@danielsimonjr/mathts-functions';
41
+ import { numberFrom } from '../core/mathts-read.js';
37
42
  /** Compute `dr/dτ = g^{rν}(x) p_ν` at a single snapshot. */
38
43
  function radialVelocity(x, p, gInverseFn, r) {
39
44
  const gInv = gInverseFn(x);
@@ -44,41 +49,25 @@ function radialVelocity(x, p, gInverseFn, r) {
44
49
  }
45
50
  return v;
46
51
  }
47
- /** Median of a numeric array (does not mutate input). */
48
- function median(values) {
49
- const sorted = [...values].sort((a, b) => a - b);
50
- const n = sorted.length;
51
- if (n === 0)
52
+ /** Median of the snapshot steps, MathTS `median` (0 for no steps, as before). */
53
+ function medianStep(values) {
54
+ if (values.length === 0)
52
55
  return 0;
53
- if (n % 2 === 1)
54
- return sorted[(n - 1) / 2];
55
- return 0.5 * (sorted[n / 2 - 1] + sorted[n / 2]);
56
+ return numberFrom('median', median([...values]));
56
57
  }
57
58
  /**
58
- * Hermite basis on the unit interval, evaluated at `s ∈ [0,1]`.
59
- *
60
- * Cubic Hermite interpolant of a scalar `f(τ)` over `[τ0, τ1]` with
59
+ * The cubic Hermite interpolant of a scalar `f(τ)` over `[τ0, τ1]` with
61
60
  * endpoint values `f0, f1` and endpoint derivatives `m0, m1` (in `f` per
62
- * `τ`):
63
- *
64
- * P(τ) = h00(s) f0 + h10(s) (τ1−τ0) m0 + h01(s) f1 + h11(s) (τ1−τ0) m1
61
+ * `τ`), at `s = (τ − τ0)/(τ1 − τ0)`: MathTS `hermiteInterp` on the two
62
+ * nodes `0` and `1` of the unit interval, where the derivatives are
63
+ * `(τ1 − τ0) m`. With two nodes that interpolant IS the cubic
65
64
  *
66
- * where `s = (τ − τ0)/(τ1 − τ0)` and
67
- * h00 = 2s³ − 3s² + 1
68
- * h10 = s³ − 2s² + s
69
- * h01 = −2s³ + 3s²
70
- * h11 = s³ − s²
65
+ * P = h00(s) f0 + h10(s) (τ1−τ0) m0 + h01(s) f1 + h11(s) (τ1−τ0) m1
71
66
  *
72
67
  * (Numerical Recipes §3.4; Hairer/Lubich/Wanner §III.5.)
73
68
  */
74
69
  function hermiteEval(f0, f1, m0, m1, dt, s) {
75
- const s2 = s * s;
76
- const s3 = s2 * s;
77
- const h00 = 2 * s3 - 3 * s2 + 1;
78
- const h10 = s3 - 2 * s2 + s;
79
- const h01 = -2 * s3 + 3 * s2;
80
- const h11 = s3 - s2;
81
- return h00 * f0 + h10 * dt * m0 + h01 * f1 + h11 * dt * m1;
70
+ return hermiteInterp([0, 1], [f0, f1], [dt * m0, dt * m1], s);
82
71
  }
83
72
  /**
84
73
  * Vector cubic-Hermite interpolation of a 4-coordinate `x^μ` at `τ`
@@ -95,61 +84,26 @@ function hermiteInterpVector(x0, x1, m0, m1, dt, s) {
95
84
  return out;
96
85
  }
97
86
  /**
98
- * Bisection on the cubic-Hermite polynomial for the scalar `dr/dτ` root.
99
- * Operates on `s ∈ [0,1]` — the normalised bracket coordinate. Returns
100
- * the converged `s` and the corresponding polynomial value.
87
+ * The root of the cubic-Hermite polynomial for the scalar `dr/dτ`, on the
88
+ * normalised bracket coordinate `s ∈ [0,1]`, by MathTS `findRoot` (Brent).
89
+ * Returns the converged `s` and the polynomial value there.
101
90
  *
102
- * Precision: the loop terminates when `|P(s_mid)| ≤ tauTolerance` (scaled
103
- * to whatever units `dr/dτ` is in — the caller passes `tauTolerance`
104
- * matched to the integrator scale). A hard iteration cap of 60 prevents
105
- * runaway on pathological inputs (60 bisections halve `s` to ≈1e-18 — well
106
- * below floating-point resolution).
91
+ * Precision: `tol` is a residual tolerance in the units of `dr/dτ` (the
92
+ * caller passes `tauTolerance`, matched to the integrator scale), so the
93
+ * solver runs with `xtol: 0` and stops on `|P(s)| ≤ tol` alone, never on
94
+ * the bracket width in `s`. `sInitial` (the linear estimate) is tried first
95
+ * and returned when it already meets `tol`. A hard iteration cap of 100
96
+ * bounds a tolerance the polynomial cannot meet in floating point; the
97
+ * solver then returns its best point.
107
98
  */
108
- function bisectCubic(f0, f1, m0, m1, dt, sInitial, tol) {
109
- // Establish a bracket around sInitial. The sign-change is at the
110
- // f(τ0)=f0 → f(τ1)=f1 endpoints (by construction f0 < 0, f1 > 0).
111
- let sLo = 0;
112
- let sHi = 1;
113
- let fLo = f0;
114
- let fHi = f1;
115
- let s = sInitial;
116
- let fs = hermiteEval(f0, f1, m0, m1, dt, s);
117
- // If sInitial already satisfies tol, return it.
118
- let absFs = fs < 0 ? -fs : fs;
119
- if (absFs <= tol)
120
- return { s, residual: fs };
121
- // Warm start: the sInitial evaluation above is otherwise discarded. Use its
122
- // sign to tighten the GUARANTEED bracket before bisecting. This preserves the
123
- // sign-bracket invariant (fLo < 0 < fHi) — so convergence is unaffected — and
124
- // a good linear estimate yields a smaller starting interval (fewer iters).
125
- if (sInitial > sLo && sInitial < sHi) {
126
- if ((fs < 0) === (fLo < 0)) {
127
- sLo = s;
128
- fLo = fs;
129
- }
130
- else {
131
- sHi = s;
132
- fHi = fs;
133
- }
134
- }
135
- for (let iter = 0; iter < 60; iter++) {
136
- // Bisect the (warm-started) bracket — robust regardless of the estimate.
137
- s = 0.5 * (sLo + sHi);
138
- fs = hermiteEval(f0, f1, m0, m1, dt, s);
139
- absFs = fs < 0 ? -fs : fs;
140
- if (absFs <= tol)
141
- return { s, residual: fs };
142
- // Maintain sign-bracket: fLo < 0 < fHi.
143
- if ((fs < 0) === (fLo < 0)) {
144
- sLo = s;
145
- fLo = fs;
146
- }
147
- else {
148
- sHi = s;
149
- fHi = fs;
150
- }
151
- }
152
- return { s, residual: fs };
99
+ function rootOnCubic(f0, f1, m0, m1, dt, sInitial, tol) {
100
+ const P = (s) => hermiteEval(f0, f1, m0, m1, dt, s);
101
+ const atStart = P(sInitial);
102
+ if (Math.abs(atStart) <= tol)
103
+ return { s: sInitial, residual: atStart };
104
+ // By construction f(0) = f0 ≤ 0 < f1 = f(1) (or f0 < 0 ≤ f1), the sign change `findRoot` requires.
105
+ const s = findRoot(P, 0, 1, { tol, xtol: 0, maxIter: 100 });
106
+ return { s, residual: P(s) };
153
107
  }
154
108
  /**
155
109
  * Find the perihelion (inner radial turning point) on a snapshot stream.
@@ -267,7 +221,7 @@ export function findPerihelion(options) {
267
221
  for (let i = 0; i < snapshots.length - 1; i++) {
268
222
  deltas.push(snapshots[i + 1].tau - snapshots[i].tau);
269
223
  }
270
- const hSnap = median(deltas);
224
+ const hSnap = medianStep(deltas);
271
225
  if (dt < hSnap) {
272
226
  process.emitWarning(`findPerihelion: bracket width Δτ=${dt} < h_snap=${hSnap} `
273
227
  + `(median snapshot step) — GL4 snapshot density is too coarse to `
@@ -284,8 +238,8 @@ export function findPerihelion(options) {
284
238
  // Initial guess: linear interpolation root, s = f0 / (f0 − f1).
285
239
  // For a linear sign-change this is exact; for cubic it's a warm start.
286
240
  const sLinear = f0 / (f0 - f1);
287
- // Step 5: bisect the cubic-Hermite polynomial until residual ≤ tolerance.
288
- const { s: sRoot } = bisectCubic(f0, f1, m0, m1, dt, sLinear, tauTolerance);
241
+ // Step 5: solve the cubic-Hermite polynomial until residual ≤ tolerance.
242
+ const { s: sRoot } = rootOnCubic(f0, f1, m0, m1, dt, sLinear, tauTolerance);
289
243
  const tauRoot = tau0 + sRoot * dt;
290
244
  // Step 6: interpolate x^μ at τ_root via cubic Hermite using the same
291
245
  // endpoint-derivative scheme. dx^μ/dτ at endpoints comes from
@@ -1 +1 @@
1
- {"version":3,"file":"perihelion-finder.js","sourceRoot":"","sources":["../../src/numerical/perihelion-finder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bisection perihelion finder via cubic-Hermite interpolation on cached\n * GL4 snapshots (v0.5.0 Task 4, Phase 1b).\n *\n * Algorithm (Design §3 Task 1b):\n * 1. Walk snapshots, extract `dr/dτ_i = g^{rν}(x_i) · p_{i,ν}` at each\n * snapshot. Index `r` is the radial coordinate slot (index 1 by\n * convention in (t, r, θ, φ)).\n * 2. Locate consecutive indices `(i, i+1)` where `dr/dτ` sign-changes\n * from `−` to `+` — that is the perihelion (inner radial turning\n * point). Sign-change `+ → −` is apoapsis and is intentionally\n * skipped.\n * 3. **M3 bracket-width check:** if `|τ_{i+1} − τ_i| < 2 · h_snap`\n * where `h_snap` is the median Δτ across all snapshots, emit a\n * non-throwing `PerihelionBracketWidthWarning` via\n * `process.emitWarning`. This indicates the GL4 step is too coarse\n * to resolve the turning point — the caller should re-integrate\n * with finer steps.\n * 4. Fit a **cubic Hermite polynomial** through `(τ_i, dr/dτ_i)` and\n * `(τ_{i+1}, dr/dτ_{i+1})`, with endpoint derivatives estimated\n * from neighboring snapshots (4 values total: f and f' at both\n * endpoints). Find an analytic root of the cubic on [τ_i, τ_{i+1}].\n * 5. If `|P(τ_root)| > tauTolerance`, refine with **bisection on the\n * polynomial** (not re-integration — Adam+Eve I6/F11 — that would\n * cost a full GL4 sweep per bisection step, which defeats the\n * cached-snapshot approach). Precision floor: 1e-9 × T_orbit\n * (Adam+Eve I1 — 1e-12 needs ~40 cubic bisections and is wasted\n * effort given the integrator's per-step error is already > 1e-12).\n * 6. Return `{ tau, x, phi }` where `x` is the cubic-Hermite-interpolated\n * 4-coordinate at the root and `phi = x[3]`.\n *\n * **Throws** `Error(\"no perihelion bracket\")` if no `−→+` sign-change is\n * found in the snapshot range.\n *\n * @module numerical/perihelion-finder\n */\n\n/**\n * Result of `findPerihelion`: the τ at the radial turning point, the\n * interpolated 4-coordinate, and the orbital phase `phi = x[3]`.\n *\n * @public\n */\nexport interface PerihelionResult {\n /** Proper time at the perihelion. */\n readonly tau: number;\n /** Interpolated 4-coordinate x^μ at τ_perihelion. */\n readonly x: readonly number[];\n /** Orbital phase φ = x[3] at τ_perihelion. */\n readonly phi: number;\n}\n\n/**\n * Options for {@link findPerihelion}.\n *\n * @public\n */\nexport interface FindPerihelionOptions {\n /** Snapshots produced by `integrateGeodesicGL4` (or any compatible\n * `(τ, x, p)` snapshot stream — only `tau`, `x`, `p` are read). */\n readonly snapshots: ReadonlyArray<{\n readonly tau: number;\n readonly x: readonly number[];\n readonly p: readonly number[];\n }>;\n /** Inverse-metric closure (v0.9.0 O-1 flat layout):\n * `gInverseFn(x)[μ*dim + ν] = g^{μν}(x)`, Float64Array(dim²). Used to\n * compute `dr/dτ = g^{rν}(x) p_ν` at each snapshot. */\n readonly gInverseFn: (x: readonly number[]) => Float64Array;\n /** Polynomial-bisection target tolerance on the cubic-Hermite root —\n * measured as `|P(τ_root)|`, not `|τ − τ_true|`. Precision floor 1e-9\n * per Adam+Eve I1; tighter values just waste bisections. */\n readonly tauTolerance: number;\n /** Coordinate index used as the \"radial\" slot. Defaults to 1\n * ((t, r, θ, φ) convention). */\n readonly radialIndex?: number;\n}\n\n/** Compute `dr/dτ = g^{rν}(x) p_ν` at a single snapshot. */\nfunction radialVelocity(\n x: readonly number[],\n p: readonly number[],\n gInverseFn: (x: readonly number[]) => Float64Array,\n r: number,\n): number {\n const gInv = gInverseFn(x);\n const dim = p.length;\n let v = 0;\n for (let nu = 0; nu < dim; nu++) {\n v += gInv[r * dim + nu] * p[nu];\n }\n return v;\n}\n\n/** Median of a numeric array (does not mutate input). */\nfunction median(values: readonly number[]): number {\n const sorted = [...values].sort((a, b) => a - b);\n const n = sorted.length;\n if (n === 0) return 0;\n if (n % 2 === 1) return sorted[(n - 1) / 2];\n return 0.5 * (sorted[n / 2 - 1] + sorted[n / 2]);\n}\n\n/**\n * Hermite basis on the unit interval, evaluated at `s ∈ [0,1]`.\n *\n * Cubic Hermite interpolant of a scalar `f(τ)` over `[τ0, τ1]` with\n * endpoint values `f0, f1` and endpoint derivatives `m0, m1` (in `f` per\n * `τ`):\n *\n * P(τ) = h00(s) f0 + h10(s) (τ1−τ0) m0 + h01(s) f1 + h11(s) (τ1−τ0) m1\n *\n * where `s = (τ − τ0)/(τ1 − τ0)` and\n * h00 = 2s³ − 3s² + 1\n * h10 = s³ − 2s² + s\n * h01 = −2s³ + 3s²\n * h11 = s³ − s²\n *\n * (Numerical Recipes §3.4; Hairer/Lubich/Wanner §III.5.)\n */\nfunction hermiteEval(\n f0: number,\n f1: number,\n m0: number,\n m1: number,\n dt: number,\n s: number,\n): number {\n const s2 = s * s;\n const s3 = s2 * s;\n const h00 = 2 * s3 - 3 * s2 + 1;\n const h10 = s3 - 2 * s2 + s;\n const h01 = -2 * s3 + 3 * s2;\n const h11 = s3 - s2;\n return h00 * f0 + h10 * dt * m0 + h01 * f1 + h11 * dt * m1;\n}\n\n/**\n * Vector cubic-Hermite interpolation of a 4-coordinate `x^μ` at `τ`\n * given the two bracket endpoints and their snapshot derivatives in `τ`\n * (here: the `x` arrays, with derivative `dx/dτ` approximated by central\n * differences on neighbor snapshots — passed in by the caller).\n */\nfunction hermiteInterpVector(\n x0: readonly number[],\n x1: readonly number[],\n m0: readonly number[],\n m1: readonly number[],\n dt: number,\n s: number,\n): number[] {\n const dim = x0.length;\n const out = new Array<number>(dim);\n for (let mu = 0; mu < dim; mu++) {\n out[mu] = hermiteEval(x0[mu], x1[mu], m0[mu], m1[mu], dt, s);\n }\n return out;\n}\n\n/**\n * Bisection on the cubic-Hermite polynomial for the scalar `dr/dτ` root.\n * Operates on `s ∈ [0,1]` — the normalised bracket coordinate. Returns\n * the converged `s` and the corresponding polynomial value.\n *\n * Precision: the loop terminates when `|P(s_mid)| ≤ tauTolerance` (scaled\n * to whatever units `dr/dτ` is in — the caller passes `tauTolerance`\n * matched to the integrator scale). A hard iteration cap of 60 prevents\n * runaway on pathological inputs (60 bisections halve `s` to ≈1e-18 — well\n * below floating-point resolution).\n */\nfunction bisectCubic(\n f0: number,\n f1: number,\n m0: number,\n m1: number,\n dt: number,\n sInitial: number,\n tol: number,\n): { s: number; residual: number } {\n // Establish a bracket around sInitial. The sign-change is at the\n // f(τ0)=f0 → f(τ1)=f1 endpoints (by construction f0 < 0, f1 > 0).\n let sLo = 0;\n let sHi = 1;\n let fLo = f0;\n let fHi = f1;\n let s = sInitial;\n let fs = hermiteEval(f0, f1, m0, m1, dt, s);\n\n // If sInitial already satisfies tol, return it.\n let absFs = fs < 0 ? -fs : fs;\n if (absFs <= tol) return { s, residual: fs };\n\n // Warm start: the sInitial evaluation above is otherwise discarded. Use its\n // sign to tighten the GUARANTEED bracket before bisecting. This preserves the\n // sign-bracket invariant (fLo < 0 < fHi) — so convergence is unaffected — and\n // a good linear estimate yields a smaller starting interval (fewer iters).\n if (sInitial > sLo && sInitial < sHi) {\n if ((fs < 0) === (fLo < 0)) {\n sLo = s;\n fLo = fs;\n } else {\n sHi = s;\n fHi = fs;\n }\n }\n\n for (let iter = 0; iter < 60; iter++) {\n // Bisect the (warm-started) bracket — robust regardless of the estimate.\n s = 0.5 * (sLo + sHi);\n fs = hermiteEval(f0, f1, m0, m1, dt, s);\n absFs = fs < 0 ? -fs : fs;\n if (absFs <= tol) return { s, residual: fs };\n // Maintain sign-bracket: fLo < 0 < fHi.\n if ((fs < 0) === (fLo < 0)) {\n sLo = s;\n fLo = fs;\n } else {\n sHi = s;\n fHi = fs;\n }\n }\n return { s, residual: fs };\n}\n\n/**\n * Find the perihelion (inner radial turning point) on a snapshot stream.\n *\n * See module-level docstring for the algorithm. Throws if no `−→+` sign\n * change in `dr/dτ` is found.\n *\n * **Units.** Inherited from the supplied snapshots and `gInverseFn` — the\n * finder is metric-agnostic. For the perihelion method used by catalog\n * relation be-52 on Schwarzschild:\n * - `snapshots[i].tau` — affine parameter in **seconds** (SI, the\n * covariant-eikonal method's null normalization, used by catalog\n * relation be-37) or **proper-time seconds** (timelike geodesics).\n * - `snapshots[i].x` — 4-coordinate `(t, r, θ, φ)` in\n * **(s, m, rad, rad)** (SI).\n * - `snapshots[i].p` — covariant momentum (units depend on the\n * normalization; see `integrateGeodesicGL4` JSDoc).\n * - `tauTolerance` — polynomial-residual tolerance on `dr/dτ`,\n * therefore in **m/s** for SI Schwarzschild. Floor `1e-9` ⇒ tighter\n * values are quietly clamped (see implementation).\n *\n * @param options — see {@link FindPerihelionOptions}:\n * - `snapshots` — `(τ, x, p)` stream from `integrateGeodesicGL4` (units\n * as above).\n * - `gInverseFn(x)[μ*dim+ν]` — inverse metric `g^{μν}(x)` (flat). Same units as\n * the matching integrator call.\n * - `tauTolerance` — bisection target on `|P(s_root)|` measured in the\n * units of `dr/dτ` (m/s for SI Schwarzschild).\n * - `radialIndex` — index of `r` within `x` (default `1` — standard\n * `(t, r, θ, φ)` ordering).\n * @returns `{ tau, x, phi }` — affine parameter, interpolated 4-coordinate,\n * and orbital phase `φ = x[3]` at the perihelion. Units of `tau` and `x`\n * match the inputs; `phi` is in **radians**.\n * @throws Error if `snapshots.length < 2` or no `−→+` sign change in `dr/dτ`.\n *\n * @example\n * ```typescript\n * import { findPerihelion, integrateGeodesicGL4 } from 'universal-physics-tensor';\n * import {\n * schwarzschildDgInverseFn,\n * schwarzschildGInverseFn,\n * schwarzschildRs,\n * } from '../tests/fixtures/schwarzschild.js';\n *\n * const M = 1.989e30;\n * const r0 = 20 * schwarzschildRs(M); // starting radius\n * // Canonical (x, p) state: covariant momentum p = [-E, 0, 0, L] from the\n * // orbit's conserved energy E and angular momentum L (see\n * // tests/bridges/perihelion-precession.test.ts for a full setup).\n * const snapshots = integrateGeodesicGL4(\n * { x: [0, r0, Math.PI / 2, 0], p: [-E, 0, 0, L] },\n * {\n * steps: 2000,\n * tauMax: 1e6,\n * gInverseFn: schwarzschildGInverseFn(M),\n * dgInverseFn: schwarzschildDgInverseFn(M),\n * },\n * );\n *\n * const perihelion = findPerihelion({\n * snapshots,\n * gInverseFn: schwarzschildGInverseFn(M),\n * tauTolerance: 1e-9,\n * });\n * // perihelion.phi — azimuthal angle at closest approach (radians)\n * ```\n *\n * @public\n */\nexport function findPerihelion(options: FindPerihelionOptions): PerihelionResult {\n const { snapshots, gInverseFn, tauTolerance, radialIndex = 1 } = options;\n if (snapshots.length < 2) {\n throw new Error('no perihelion bracket: need at least 2 snapshots');\n }\n\n // Step 1: extract dr/dτ at every snapshot.\n const drDtau = new Array<number>(snapshots.length);\n for (let i = 0; i < snapshots.length; i++) {\n drDtau[i] = radialVelocity(\n snapshots[i].x,\n snapshots[i].p,\n gInverseFn,\n radialIndex,\n );\n }\n\n // Step 2: locate the first `− → +` sign change.\n // Tolerant against snapshot landing exactly at the turning point\n // (drDtau ≈ 0): treat `≤ 0 → > 0` as a valid bracket. A snapshot with\n // f == 0 exactly is itself the perihelion — but we still return through\n // the Hermite path so the {x, phi} interpolation is uniform.\n let iBracket = -1;\n for (let i = 0; i < snapshots.length - 1; i++) {\n if (drDtau[i] <= 0 && drDtau[i + 1] > 0) {\n iBracket = i;\n break;\n }\n if (drDtau[i] < 0 && drDtau[i + 1] >= 0) {\n iBracket = i;\n break;\n }\n }\n if (iBracket < 0) {\n throw new Error('no perihelion bracket: dr/dτ does not change sign − → +');\n }\n\n const i0 = iBracket;\n const i1 = iBracket + 1;\n const tau0 = snapshots[i0].tau;\n const tau1 = snapshots[i1].tau;\n const dt = tau1 - tau0;\n\n // Step 3: M3 bracket-width check vs median Δτ.\n //\n // Plan spec literally says `< 2·h_snap`, but on a uniform-step grid\n // every bracket equals h_snap exactly (ratio 1.0), so `< 2·h_snap` would\n // fire on every successful call — useless as a diagnostic. The intent\n // of M3 is to flag brackets compressed below the nominal integrator\n // step (i.e., adaptive step-halving has run near perihelion, leaving a\n // suspicious cluster). We compare against `h_snap` directly: the\n // warning fires when the bracket is **narrower than the typical step**.\n // Documented deviation; honest framing maintained — see CHANGELOG.\n const deltas: number[] = [];\n for (let i = 0; i < snapshots.length - 1; i++) {\n deltas.push(snapshots[i + 1].tau - snapshots[i].tau);\n }\n const hSnap = median(deltas);\n if (dt < hSnap) {\n process.emitWarning(\n `findPerihelion: bracket width Δτ=${dt} < h_snap=${hSnap} `\n + `(median snapshot step) — GL4 snapshot density is too coarse to `\n + `resolve this turning point reliably; consider re-integrating `\n + `with finer steps.`,\n 'PerihelionBracketWidthWarning',\n );\n }\n\n // Step 4: build cubic-Hermite interpolant for dr/dτ on [τ_i0, τ_i1].\n // Endpoint derivatives (d/dτ of dr/dτ) approximated via central\n // differences on neighboring snapshots (one-sided at boundaries).\n const f0 = drDtau[i0];\n const f1 = drDtau[i1];\n const m0 = derivAt(drDtau, snapshots, i0);\n const m1 = derivAt(drDtau, snapshots, i1);\n\n // Initial guess: linear interpolation root, s = f0 / (f0 − f1).\n // For a linear sign-change this is exact; for cubic it's a warm start.\n const sLinear = f0 / (f0 - f1);\n\n // Step 5: bisect the cubic-Hermite polynomial until residual ≤ tolerance.\n const { s: sRoot } = bisectCubic(f0, f1, m0, m1, dt, sLinear, tauTolerance);\n\n const tauRoot = tau0 + sRoot * dt;\n\n // Step 6: interpolate x^μ at τ_root via cubic Hermite using the same\n // endpoint-derivative scheme. dx^μ/dτ at endpoints comes from\n // central-differencing neighboring snapshots' x arrays.\n const xMomentum0 = velocityAt(snapshots, i0, gInverseFn);\n const xMomentum1 = velocityAt(snapshots, i1, gInverseFn);\n const xInterp = hermiteInterpVector(\n snapshots[i0].x,\n snapshots[i1].x,\n xMomentum0,\n xMomentum1,\n dt,\n sRoot,\n );\n\n return {\n tau: tauRoot,\n x: xInterp,\n phi: xInterp[3] ?? 0,\n };\n}\n\n/**\n * Central-difference estimate of `d(dr/dτ)/dτ` at snapshot index `i`.\n * One-sided at i=0 and i=N−1. Used as the Hermite endpoint slope.\n */\nfunction derivAt(\n drDtau: readonly number[],\n snapshots: ReadonlyArray<{ readonly tau: number }>,\n i: number,\n): number {\n const N = snapshots.length;\n if (i === 0) {\n return (drDtau[1] - drDtau[0]) / (snapshots[1].tau - snapshots[0].tau);\n }\n if (i === N - 1) {\n return (drDtau[N - 1] - drDtau[N - 2])\n / (snapshots[N - 1].tau - snapshots[N - 2].tau);\n }\n return (drDtau[i + 1] - drDtau[i - 1])\n / (snapshots[i + 1].tau - snapshots[i - 1].tau);\n}\n\n/**\n * 4-velocity `v^μ = g^{μν}(x_i) p_{i,ν}` at snapshot `i`. Used as the\n * Hermite endpoint slope for the `x^μ` interpolation (since by definition\n * `dx^μ/dτ = g^{μν} p_ν` along a geodesic).\n */\nfunction velocityAt(\n snapshots: ReadonlyArray<{ readonly x: readonly number[]; readonly p: readonly number[] }>,\n i: number,\n gInverseFn: (x: readonly number[]) => Float64Array,\n): number[] {\n const x = snapshots[i].x;\n const p = snapshots[i].p;\n const gInv = gInverseFn(x);\n const dim = x.length;\n const v = new Array<number>(dim);\n for (let mu = 0; mu < dim; mu++) {\n let acc = 0;\n for (let nu = 0; nu < dim; nu++) {\n acc += gInv[mu * dim + nu] * p[nu];\n }\n v[mu] = acc;\n }\n return v;\n}\n"]}
1
+ {"version":3,"file":"perihelion-finder.js","sourceRoot":"","sources":["../../src/numerical/perihelion-finder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bisection perihelion finder via cubic-Hermite interpolation on cached\n * GL4 snapshots (v0.5.0 Task 4, Phase 1b).\n *\n * Algorithm (Design §3 Task 1b):\n * 1. Walk snapshots, extract `dr/dτ_i = g^{rν}(x_i) · p_{i,ν}` at each\n * snapshot. Index `r` is the radial coordinate slot (index 1 by\n * convention in (t, r, θ, φ)).\n * 2. Locate consecutive indices `(i, i+1)` where `dr/dτ` sign-changes\n * from `−` to `+` — that is the perihelion (inner radial turning\n * point). Sign-change `+ → −` is apoapsis and is intentionally\n * skipped.\n * 3. **M3 bracket-width check:** if `|τ_{i+1} − τ_i| < 2 · h_snap`\n * where `h_snap` is the median Δτ across all snapshots, emit a\n * non-throwing `PerihelionBracketWidthWarning` via\n * `process.emitWarning`. This indicates the GL4 step is too coarse\n * to resolve the turning point — the caller should re-integrate\n * with finer steps.\n * 4. Fit a **cubic Hermite polynomial** through `(τ_i, dr/dτ_i)` and\n * `(τ_{i+1}, dr/dτ_{i+1})`, with endpoint derivatives estimated\n * from neighboring snapshots (4 values total: f and f' at both\n * endpoints). Find an analytic root of the cubic on [τ_i, τ_{i+1}].\n * 5. If `|P(τ_root)| > tauTolerance`, refine with **Brent's method on the\n * polynomial** (MathTS `findRoot`, not re-integration — Adam+Eve\n * I6/F11 — that would cost a full GL4 sweep per step, which defeats\n * the cached-snapshot approach). `tauTolerance` is a RESIDUAL tolerance\n * in the units of dr/dτ, so the search is run with `xtol: 0`\n * (`@danielsimonjr/mathts-functions` ≥ 0.68.3): the solver stops on\n * `|P| ≤ tauTolerance` alone, never on the bracket width in `s`.\n * Precision floor: 1e-9 × T_orbit (Adam+Eve I1 — 1e-12 is wasted\n * effort given the integrator's per-step error is already > 1e-12).\n * 6. Return `{ tau, x, phi }` where `x` is the cubic-Hermite-interpolated\n * 4-coordinate at the root and `phi = x[3]`.\n *\n * **Throws** `Error(\"no perihelion bracket\")` if no `−→+` sign-change is\n * found in the snapshot range.\n *\n * @module numerical/perihelion-finder\n */\nimport { findRoot, hermiteInterp, median } from '@danielsimonjr/mathts-functions';\nimport { numberFrom } from '../core/mathts-read.js';\n\n/**\n * Result of `findPerihelion`: the τ at the radial turning point, the\n * interpolated 4-coordinate, and the orbital phase `phi = x[3]`.\n *\n * @public\n */\nexport interface PerihelionResult {\n /** Proper time at the perihelion. */\n readonly tau: number;\n /** Interpolated 4-coordinate x^μ at τ_perihelion. */\n readonly x: readonly number[];\n /** Orbital phase φ = x[3] at τ_perihelion. */\n readonly phi: number;\n}\n\n/**\n * Options for {@link findPerihelion}.\n *\n * @public\n */\nexport interface FindPerihelionOptions {\n /** Snapshots produced by `integrateGeodesicGL4` (or any compatible\n * `(τ, x, p)` snapshot stream — only `tau`, `x`, `p` are read). */\n readonly snapshots: ReadonlyArray<{\n readonly tau: number;\n readonly x: readonly number[];\n readonly p: readonly number[];\n }>;\n /** Inverse-metric closure (v0.9.0 O-1 flat layout):\n * `gInverseFn(x)[μ*dim + ν] = g^{μν}(x)`, Float64Array(dim²). Used to\n * compute `dr/dτ = g^{rν}(x) p_ν` at each snapshot. */\n readonly gInverseFn: (x: readonly number[]) => Float64Array;\n /** Polynomial-bisection target tolerance on the cubic-Hermite root —\n * measured as `|P(τ_root)|`, not `|τ − τ_true|`. Precision floor 1e-9\n * per Adam+Eve I1; tighter values just waste bisections. */\n readonly tauTolerance: number;\n /** Coordinate index used as the \"radial\" slot. Defaults to 1\n * ((t, r, θ, φ) convention). */\n readonly radialIndex?: number;\n}\n\n/** Compute `dr/dτ = g^{rν}(x) p_ν` at a single snapshot. */\nfunction radialVelocity(\n x: readonly number[],\n p: readonly number[],\n gInverseFn: (x: readonly number[]) => Float64Array,\n r: number,\n): number {\n const gInv = gInverseFn(x);\n const dim = p.length;\n let v = 0;\n for (let nu = 0; nu < dim; nu++) {\n v += gInv[r * dim + nu] * p[nu];\n }\n return v;\n}\n\n/** Median of the snapshot steps, MathTS `median` (0 for no steps, as before). */\nfunction medianStep(values: readonly number[]): number {\n if (values.length === 0) return 0;\n return numberFrom('median', median([...values]));\n}\n\n/**\n * The cubic Hermite interpolant of a scalar `f(τ)` over `[τ0, τ1]` with\n * endpoint values `f0, f1` and endpoint derivatives `m0, m1` (in `f` per\n * `τ`), at `s = (τ − τ0)/(τ1 − τ0)`: MathTS `hermiteInterp` on the two\n * nodes `0` and `1` of the unit interval, where the derivatives are\n * `(τ1 − τ0) m`. With two nodes that interpolant IS the cubic\n *\n * P = h00(s) f0 + h10(s) (τ1−τ0) m0 + h01(s) f1 + h11(s) (τ1−τ0) m1\n *\n * (Numerical Recipes §3.4; Hairer/Lubich/Wanner §III.5.)\n */\nfunction hermiteEval(\n f0: number,\n f1: number,\n m0: number,\n m1: number,\n dt: number,\n s: number,\n): number {\n return hermiteInterp([0, 1], [f0, f1], [dt * m0, dt * m1], s);\n}\n\n/**\n * Vector cubic-Hermite interpolation of a 4-coordinate `x^μ` at `τ`\n * given the two bracket endpoints and their snapshot derivatives in `τ`\n * (here: the `x` arrays, with derivative `dx/dτ` approximated by central\n * differences on neighbor snapshots — passed in by the caller).\n */\nfunction hermiteInterpVector(\n x0: readonly number[],\n x1: readonly number[],\n m0: readonly number[],\n m1: readonly number[],\n dt: number,\n s: number,\n): number[] {\n const dim = x0.length;\n const out = new Array<number>(dim);\n for (let mu = 0; mu < dim; mu++) {\n out[mu] = hermiteEval(x0[mu], x1[mu], m0[mu], m1[mu], dt, s);\n }\n return out;\n}\n\n/**\n * The root of the cubic-Hermite polynomial for the scalar `dr/dτ`, on the\n * normalised bracket coordinate `s ∈ [0,1]`, by MathTS `findRoot` (Brent).\n * Returns the converged `s` and the polynomial value there.\n *\n * Precision: `tol` is a residual tolerance in the units of `dr/dτ` (the\n * caller passes `tauTolerance`, matched to the integrator scale), so the\n * solver runs with `xtol: 0` and stops on `|P(s)| ≤ tol` alone, never on\n * the bracket width in `s`. `sInitial` (the linear estimate) is tried first\n * and returned when it already meets `tol`. A hard iteration cap of 100\n * bounds a tolerance the polynomial cannot meet in floating point; the\n * solver then returns its best point.\n */\nfunction rootOnCubic(\n f0: number,\n f1: number,\n m0: number,\n m1: number,\n dt: number,\n sInitial: number,\n tol: number,\n): { s: number; residual: number } {\n const P = (s: number): number => hermiteEval(f0, f1, m0, m1, dt, s);\n const atStart = P(sInitial);\n if (Math.abs(atStart) <= tol) return { s: sInitial, residual: atStart };\n // By construction f(0) = f0 ≤ 0 < f1 = f(1) (or f0 < 0 ≤ f1), the sign change `findRoot` requires.\n const s = findRoot(P, 0, 1, { tol, xtol: 0, maxIter: 100 });\n return { s, residual: P(s) };\n}\n\n/**\n * Find the perihelion (inner radial turning point) on a snapshot stream.\n *\n * See module-level docstring for the algorithm. Throws if no `−→+` sign\n * change in `dr/dτ` is found.\n *\n * **Units.** Inherited from the supplied snapshots and `gInverseFn` — the\n * finder is metric-agnostic. For the perihelion method used by catalog\n * relation be-52 on Schwarzschild:\n * - `snapshots[i].tau` — affine parameter in **seconds** (SI, the\n * covariant-eikonal method's null normalization, used by catalog\n * relation be-37) or **proper-time seconds** (timelike geodesics).\n * - `snapshots[i].x` — 4-coordinate `(t, r, θ, φ)` in\n * **(s, m, rad, rad)** (SI).\n * - `snapshots[i].p` — covariant momentum (units depend on the\n * normalization; see `integrateGeodesicGL4` JSDoc).\n * - `tauTolerance` — polynomial-residual tolerance on `dr/dτ`,\n * therefore in **m/s** for SI Schwarzschild. Floor `1e-9` ⇒ tighter\n * values are quietly clamped (see implementation).\n *\n * @param options — see {@link FindPerihelionOptions}:\n * - `snapshots` — `(τ, x, p)` stream from `integrateGeodesicGL4` (units\n * as above).\n * - `gInverseFn(x)[μ*dim+ν]` — inverse metric `g^{μν}(x)` (flat). Same units as\n * the matching integrator call.\n * - `tauTolerance` — bisection target on `|P(s_root)|` measured in the\n * units of `dr/dτ` (m/s for SI Schwarzschild).\n * - `radialIndex` — index of `r` within `x` (default `1` — standard\n * `(t, r, θ, φ)` ordering).\n * @returns `{ tau, x, phi }` — affine parameter, interpolated 4-coordinate,\n * and orbital phase `φ = x[3]` at the perihelion. Units of `tau` and `x`\n * match the inputs; `phi` is in **radians**.\n * @throws Error if `snapshots.length < 2` or no `−→+` sign change in `dr/dτ`.\n *\n * @example\n * ```typescript\n * import { findPerihelion, integrateGeodesicGL4 } from 'universal-physics-tensor';\n * import {\n * schwarzschildDgInverseFn,\n * schwarzschildGInverseFn,\n * schwarzschildRs,\n * } from '../tests/fixtures/schwarzschild.js';\n *\n * const M = 1.989e30;\n * const r0 = 20 * schwarzschildRs(M); // starting radius\n * // Canonical (x, p) state: covariant momentum p = [-E, 0, 0, L] from the\n * // orbit's conserved energy E and angular momentum L (see\n * // tests/bridges/perihelion-precession.test.ts for a full setup).\n * const snapshots = integrateGeodesicGL4(\n * { x: [0, r0, Math.PI / 2, 0], p: [-E, 0, 0, L] },\n * {\n * steps: 2000,\n * tauMax: 1e6,\n * gInverseFn: schwarzschildGInverseFn(M),\n * dgInverseFn: schwarzschildDgInverseFn(M),\n * },\n * );\n *\n * const perihelion = findPerihelion({\n * snapshots,\n * gInverseFn: schwarzschildGInverseFn(M),\n * tauTolerance: 1e-9,\n * });\n * // perihelion.phi — azimuthal angle at closest approach (radians)\n * ```\n *\n * @public\n */\nexport function findPerihelion(options: FindPerihelionOptions): PerihelionResult {\n const { snapshots, gInverseFn, tauTolerance, radialIndex = 1 } = options;\n if (snapshots.length < 2) {\n throw new Error('no perihelion bracket: need at least 2 snapshots');\n }\n\n // Step 1: extract dr/dτ at every snapshot.\n const drDtau = new Array<number>(snapshots.length);\n for (let i = 0; i < snapshots.length; i++) {\n drDtau[i] = radialVelocity(\n snapshots[i].x,\n snapshots[i].p,\n gInverseFn,\n radialIndex,\n );\n }\n\n // Step 2: locate the first `− → +` sign change.\n // Tolerant against snapshot landing exactly at the turning point\n // (drDtau ≈ 0): treat `≤ 0 → > 0` as a valid bracket. A snapshot with\n // f == 0 exactly is itself the perihelion — but we still return through\n // the Hermite path so the {x, phi} interpolation is uniform.\n let iBracket = -1;\n for (let i = 0; i < snapshots.length - 1; i++) {\n if (drDtau[i] <= 0 && drDtau[i + 1] > 0) {\n iBracket = i;\n break;\n }\n if (drDtau[i] < 0 && drDtau[i + 1] >= 0) {\n iBracket = i;\n break;\n }\n }\n if (iBracket < 0) {\n throw new Error('no perihelion bracket: dr/dτ does not change sign − → +');\n }\n\n const i0 = iBracket;\n const i1 = iBracket + 1;\n const tau0 = snapshots[i0].tau;\n const tau1 = snapshots[i1].tau;\n const dt = tau1 - tau0;\n\n // Step 3: M3 bracket-width check vs median Δτ.\n //\n // Plan spec literally says `< 2·h_snap`, but on a uniform-step grid\n // every bracket equals h_snap exactly (ratio 1.0), so `< 2·h_snap` would\n // fire on every successful call — useless as a diagnostic. The intent\n // of M3 is to flag brackets compressed below the nominal integrator\n // step (i.e., adaptive step-halving has run near perihelion, leaving a\n // suspicious cluster). We compare against `h_snap` directly: the\n // warning fires when the bracket is **narrower than the typical step**.\n // Documented deviation; honest framing maintained — see CHANGELOG.\n const deltas: number[] = [];\n for (let i = 0; i < snapshots.length - 1; i++) {\n deltas.push(snapshots[i + 1].tau - snapshots[i].tau);\n }\n const hSnap = medianStep(deltas);\n if (dt < hSnap) {\n process.emitWarning(\n `findPerihelion: bracket width Δτ=${dt} < h_snap=${hSnap} `\n + `(median snapshot step) — GL4 snapshot density is too coarse to `\n + `resolve this turning point reliably; consider re-integrating `\n + `with finer steps.`,\n 'PerihelionBracketWidthWarning',\n );\n }\n\n // Step 4: build cubic-Hermite interpolant for dr/dτ on [τ_i0, τ_i1].\n // Endpoint derivatives (d/dτ of dr/dτ) approximated via central\n // differences on neighboring snapshots (one-sided at boundaries).\n const f0 = drDtau[i0];\n const f1 = drDtau[i1];\n const m0 = derivAt(drDtau, snapshots, i0);\n const m1 = derivAt(drDtau, snapshots, i1);\n\n // Initial guess: linear interpolation root, s = f0 / (f0 − f1).\n // For a linear sign-change this is exact; for cubic it's a warm start.\n const sLinear = f0 / (f0 - f1);\n\n // Step 5: solve the cubic-Hermite polynomial until residual ≤ tolerance.\n const { s: sRoot } = rootOnCubic(f0, f1, m0, m1, dt, sLinear, tauTolerance);\n\n const tauRoot = tau0 + sRoot * dt;\n\n // Step 6: interpolate x^μ at τ_root via cubic Hermite using the same\n // endpoint-derivative scheme. dx^μ/dτ at endpoints comes from\n // central-differencing neighboring snapshots' x arrays.\n const xMomentum0 = velocityAt(snapshots, i0, gInverseFn);\n const xMomentum1 = velocityAt(snapshots, i1, gInverseFn);\n const xInterp = hermiteInterpVector(\n snapshots[i0].x,\n snapshots[i1].x,\n xMomentum0,\n xMomentum1,\n dt,\n sRoot,\n );\n\n return {\n tau: tauRoot,\n x: xInterp,\n phi: xInterp[3] ?? 0,\n };\n}\n\n/**\n * Central-difference estimate of `d(dr/dτ)/dτ` at snapshot index `i`.\n * One-sided at i=0 and i=N−1. Used as the Hermite endpoint slope.\n */\nfunction derivAt(\n drDtau: readonly number[],\n snapshots: ReadonlyArray<{ readonly tau: number }>,\n i: number,\n): number {\n const N = snapshots.length;\n if (i === 0) {\n return (drDtau[1] - drDtau[0]) / (snapshots[1].tau - snapshots[0].tau);\n }\n if (i === N - 1) {\n return (drDtau[N - 1] - drDtau[N - 2])\n / (snapshots[N - 1].tau - snapshots[N - 2].tau);\n }\n return (drDtau[i + 1] - drDtau[i - 1])\n / (snapshots[i + 1].tau - snapshots[i - 1].tau);\n}\n\n/**\n * 4-velocity `v^μ = g^{μν}(x_i) p_{i,ν}` at snapshot `i`. Used as the\n * Hermite endpoint slope for the `x^μ` interpolation (since by definition\n * `dx^μ/dτ = g^{μν} p_ν` along a geodesic).\n */\nfunction velocityAt(\n snapshots: ReadonlyArray<{ readonly x: readonly number[]; readonly p: readonly number[] }>,\n i: number,\n gInverseFn: (x: readonly number[]) => Float64Array,\n): number[] {\n const x = snapshots[i].x;\n const p = snapshots[i].p;\n const gInv = gInverseFn(x);\n const dim = x.length;\n const v = new Array<number>(dim);\n for (let mu = 0; mu < dim; mu++) {\n let acc = 0;\n for (let nu = 0; nu < dim; nu++) {\n acc += gInv[mu * dim + nu] * p[nu];\n }\n v[mu] = acc;\n }\n return v;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"quadrature.d.ts","sourceRoot":"","sources":["../../src/numerical/quadrature.ts"],"names":[],"mappings":"AAqBA,yFAAyF;AACzF,UAAU,iBAAiB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAgBD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,CAG7D,CAAC;AAEH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACxB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,CAmBR"}
1
+ {"version":3,"file":"quadrature.d.ts","sourceRoot":"","sources":["../../src/numerical/quadrature.ts"],"names":[],"mappings":"AAsBA,yFAAyF;AACzF,UAAU,iBAAiB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAcD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,CAG7D,CAAC;AAEH;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACxB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,CAmBR"}