universal-physics-tensor 0.5.0 → 0.7.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 (401) hide show
  1. package/README.md +66 -105
  2. package/dist/bridges/catalog-adapter.d.ts +116 -0
  3. package/dist/bridges/catalog-adapter.d.ts.map +1 -0
  4. package/dist/bridges/catalog-adapter.js +302 -0
  5. package/dist/bridges/catalog-adapter.js.map +1 -0
  6. package/dist/bridges/equations/_be-helpers.d.ts +145 -0
  7. package/dist/bridges/equations/_be-helpers.d.ts.map +1 -0
  8. package/dist/bridges/equations/_be-helpers.js +179 -0
  9. package/dist/bridges/equations/_be-helpers.js.map +1 -0
  10. package/dist/bridges/equations/be-11-decoherence-master.d.ts +1 -2
  11. package/dist/bridges/equations/be-11-decoherence-master.d.ts.map +1 -1
  12. package/dist/bridges/equations/be-11-decoherence-master.js +9 -20
  13. package/dist/bridges/equations/be-11-decoherence-master.js.map +1 -1
  14. package/dist/bridges/equations/be-12-coherence-length.d.ts +7 -1
  15. package/dist/bridges/equations/be-12-coherence-length.d.ts.map +1 -1
  16. package/dist/bridges/equations/be-12-coherence-length.js +8 -16
  17. package/dist/bridges/equations/be-12-coherence-length.js.map +1 -1
  18. package/dist/bridges/equations/be-13-einstein-trace.d.ts +51 -3
  19. package/dist/bridges/equations/be-13-einstein-trace.d.ts.map +1 -1
  20. package/dist/bridges/equations/be-13-einstein-trace.js +74 -17
  21. package/dist/bridges/equations/be-13-einstein-trace.js.map +1 -1
  22. package/dist/bridges/equations/be-14-ryu-takayanagi.d.ts +10 -4
  23. package/dist/bridges/equations/be-14-ryu-takayanagi.d.ts.map +1 -1
  24. package/dist/bridges/equations/be-14-ryu-takayanagi.js +6 -17
  25. package/dist/bridges/equations/be-14-ryu-takayanagi.js.map +1 -1
  26. package/dist/bridges/equations/be-15-emergence.d.ts +7 -1
  27. package/dist/bridges/equations/be-15-emergence.d.ts.map +1 -1
  28. package/dist/bridges/equations/be-15-emergence.js +12 -22
  29. package/dist/bridges/equations/be-15-emergence.js.map +1 -1
  30. package/dist/bridges/equations/be-16-landauer.d.ts +7 -1
  31. package/dist/bridges/equations/be-16-landauer.d.ts.map +1 -1
  32. package/dist/bridges/equations/be-16-landauer.js +5 -13
  33. package/dist/bridges/equations/be-16-landauer.js.map +1 -1
  34. package/dist/bridges/equations/be-17-einstein-cartan.d.ts +26 -13
  35. package/dist/bridges/equations/be-17-einstein-cartan.d.ts.map +1 -1
  36. package/dist/bridges/equations/be-17-einstein-cartan.js +28 -31
  37. package/dist/bridges/equations/be-17-einstein-cartan.js.map +1 -1
  38. package/dist/bridges/equations/be-18-higgs-mass.d.ts +7 -1
  39. package/dist/bridges/equations/be-18-higgs-mass.d.ts.map +1 -1
  40. package/dist/bridges/equations/be-18-higgs-mass.js +5 -16
  41. package/dist/bridges/equations/be-18-higgs-mass.js.map +1 -1
  42. package/dist/bridges/equations/be-19-quantum-bounce.d.ts +38 -3
  43. package/dist/bridges/equations/be-19-quantum-bounce.d.ts.map +1 -1
  44. package/dist/bridges/equations/be-19-quantum-bounce.js +69 -20
  45. package/dist/bridges/equations/be-19-quantum-bounce.js.map +1 -1
  46. package/dist/bridges/equations/be-20-vacuum-energy.d.ts +20 -1
  47. package/dist/bridges/equations/be-20-vacuum-energy.d.ts.map +1 -1
  48. package/dist/bridges/equations/be-20-vacuum-energy.js +36 -15
  49. package/dist/bridges/equations/be-20-vacuum-energy.js.map +1 -1
  50. package/dist/bridges/equations/be-21-kss-bound.d.ts +2 -0
  51. package/dist/bridges/equations/be-21-kss-bound.d.ts.map +1 -1
  52. package/dist/bridges/equations/be-21-kss-bound.js +4 -10
  53. package/dist/bridges/equations/be-21-kss-bound.js.map +1 -1
  54. package/dist/bridges/equations/be-22-topological-entanglement.d.ts +6 -9
  55. package/dist/bridges/equations/be-22-topological-entanglement.d.ts.map +1 -1
  56. package/dist/bridges/equations/be-22-topological-entanglement.js +9 -21
  57. package/dist/bridges/equations/be-22-topological-entanglement.js.map +1 -1
  58. package/dist/bridges/equations/be-23-syk-planckian.d.ts +7 -1
  59. package/dist/bridges/equations/be-23-syk-planckian.d.ts.map +1 -1
  60. package/dist/bridges/equations/be-23-syk-planckian.js +11 -25
  61. package/dist/bridges/equations/be-23-syk-planckian.js.map +1 -1
  62. package/dist/bridges/equations/be-24-foerster-fret.d.ts +7 -1
  63. package/dist/bridges/equations/be-24-foerster-fret.d.ts.map +1 -1
  64. package/dist/bridges/equations/be-24-foerster-fret.js +8 -16
  65. package/dist/bridges/equations/be-24-foerster-fret.js.map +1 -1
  66. package/dist/bridges/equations/be-25-iit-phi.d.ts +7 -1
  67. package/dist/bridges/equations/be-25-iit-phi.d.ts.map +1 -1
  68. package/dist/bridges/equations/be-25-iit-phi.js +12 -16
  69. package/dist/bridges/equations/be-25-iit-phi.js.map +1 -1
  70. package/dist/bridges/equations/be-25-orch-or.d.ts +6 -3
  71. package/dist/bridges/equations/be-25-orch-or.d.ts.map +1 -1
  72. package/dist/bridges/equations/be-25-orch-or.js +8 -17
  73. package/dist/bridges/equations/be-25-orch-or.js.map +1 -1
  74. package/dist/bridges/equations/be-26-dna-tunneling.d.ts +6 -3
  75. package/dist/bridges/equations/be-26-dna-tunneling.d.ts.map +1 -1
  76. package/dist/bridges/equations/be-26-dna-tunneling.js +11 -26
  77. package/dist/bridges/equations/be-26-dna-tunneling.js.map +1 -1
  78. package/dist/bridges/equations/be-27-effective-temperature.d.ts +7 -1
  79. package/dist/bridges/equations/be-27-effective-temperature.d.ts.map +1 -1
  80. package/dist/bridges/equations/be-27-effective-temperature.js +8 -16
  81. package/dist/bridges/equations/be-27-effective-temperature.js.map +1 -1
  82. package/dist/bridges/equations/be-28-onsager-entropy-production.d.ts +7 -1
  83. package/dist/bridges/equations/be-28-onsager-entropy-production.d.ts.map +1 -1
  84. package/dist/bridges/equations/be-28-onsager-entropy-production.js +9 -13
  85. package/dist/bridges/equations/be-28-onsager-entropy-production.js.map +1 -1
  86. package/dist/bridges/equations/be-29-jarzynski.d.ts +7 -1
  87. package/dist/bridges/equations/be-29-jarzynski.d.ts.map +1 -1
  88. package/dist/bridges/equations/be-29-jarzynski.js +8 -13
  89. package/dist/bridges/equations/be-29-jarzynski.js.map +1 -1
  90. package/dist/bridges/equations/be-30-flm-first-law.d.ts +11 -2
  91. package/dist/bridges/equations/be-30-flm-first-law.d.ts.map +1 -1
  92. package/dist/bridges/equations/be-30-flm-first-law.js +10 -21
  93. package/dist/bridges/equations/be-30-flm-first-law.js.map +1 -1
  94. package/dist/bridges/equations/be-31-causal-set-bd.d.ts +7 -1
  95. package/dist/bridges/equations/be-31-causal-set-bd.d.ts.map +1 -1
  96. package/dist/bridges/equations/be-31-causal-set-bd.js +11 -25
  97. package/dist/bridges/equations/be-31-causal-set-bd.js.map +1 -1
  98. package/dist/bridges/equations/be-32-quantum-reference-frame.d.ts +6 -9
  99. package/dist/bridges/equations/be-32-quantum-reference-frame.d.ts.map +1 -1
  100. package/dist/bridges/equations/be-32-quantum-reference-frame.js +8 -18
  101. package/dist/bridges/equations/be-32-quantum-reference-frame.js.map +1 -1
  102. package/dist/bridges/equations/be-33-hertz-millis.d.ts +53 -28
  103. package/dist/bridges/equations/be-33-hertz-millis.d.ts.map +1 -1
  104. package/dist/bridges/equations/be-33-hertz-millis.js +55 -51
  105. package/dist/bridges/equations/be-33-hertz-millis.js.map +1 -1
  106. package/dist/bridges/equations/be-34-kibble-zurek.d.ts +6 -3
  107. package/dist/bridges/equations/be-34-kibble-zurek.d.ts.map +1 -1
  108. package/dist/bridges/equations/be-34-kibble-zurek.js +15 -26
  109. package/dist/bridges/equations/be-34-kibble-zurek.js.map +1 -1
  110. package/dist/bridges/equations/be-35-conformal-bootstrap.d.ts +6 -9
  111. package/dist/bridges/equations/be-35-conformal-bootstrap.d.ts.map +1 -1
  112. package/dist/bridges/equations/be-35-conformal-bootstrap.js +9 -21
  113. package/dist/bridges/equations/be-35-conformal-bootstrap.js.map +1 -1
  114. package/dist/bridges/equations/be-36-gw-speed-bound.d.ts +7 -1
  115. package/dist/bridges/equations/be-36-gw-speed-bound.d.ts.map +1 -1
  116. package/dist/bridges/equations/be-36-gw-speed-bound.js +5 -13
  117. package/dist/bridges/equations/be-36-gw-speed-bound.js.map +1 -1
  118. package/dist/bridges/equations/be-37-shapiro-delay.d.ts +4 -2
  119. package/dist/bridges/equations/be-37-shapiro-delay.d.ts.map +1 -1
  120. package/dist/bridges/equations/be-37-shapiro-delay.js +22 -37
  121. package/dist/bridges/equations/be-37-shapiro-delay.js.map +1 -1
  122. package/dist/bridges/equations/be-38-mond.d.ts +7 -1
  123. package/dist/bridges/equations/be-38-mond.d.ts.map +1 -1
  124. package/dist/bridges/equations/be-38-mond.js +9 -19
  125. package/dist/bridges/equations/be-38-mond.js.map +1 -1
  126. package/dist/bridges/equations/be-39-asymptotic-safety.d.ts +66 -2
  127. package/dist/bridges/equations/be-39-asymptotic-safety.d.ts.map +1 -1
  128. package/dist/bridges/equations/be-39-asymptotic-safety.js +128 -20
  129. package/dist/bridges/equations/be-39-asymptotic-safety.js.map +1 -1
  130. package/dist/bridges/equations/be-40-composite-higgs.d.ts +7 -1
  131. package/dist/bridges/equations/be-40-composite-higgs.d.ts.map +1 -1
  132. package/dist/bridges/equations/be-40-composite-higgs.js +10 -22
  133. package/dist/bridges/equations/be-40-composite-higgs.js.map +1 -1
  134. package/dist/bridges/equations/be-41-swampland.d.ts +6 -3
  135. package/dist/bridges/equations/be-41-swampland.d.ts.map +1 -1
  136. package/dist/bridges/equations/be-41-swampland.js +11 -23
  137. package/dist/bridges/equations/be-41-swampland.js.map +1 -1
  138. package/dist/bridges/equations/be-42-hawking-temperature.d.ts +2 -0
  139. package/dist/bridges/equations/be-42-hawking-temperature.d.ts.map +1 -1
  140. package/dist/bridges/equations/be-42-hawking-temperature.js +5 -13
  141. package/dist/bridges/equations/be-42-hawking-temperature.js.map +1 -1
  142. package/dist/bridges/equations/be-43-er-epr.d.ts +7 -1
  143. package/dist/bridges/equations/be-43-er-epr.d.ts.map +1 -1
  144. package/dist/bridges/equations/be-43-er-epr.js +5 -13
  145. package/dist/bridges/equations/be-43-er-epr.js.map +1 -1
  146. package/dist/bridges/equations/be-44-soft-hair.d.ts +7 -1
  147. package/dist/bridges/equations/be-44-soft-hair.d.ts.map +1 -1
  148. package/dist/bridges/equations/be-44-soft-hair.js +5 -13
  149. package/dist/bridges/equations/be-44-soft-hair.js.map +1 -1
  150. package/dist/bridges/equations/be-45-tcc.d.ts +7 -1
  151. package/dist/bridges/equations/be-45-tcc.d.ts.map +1 -1
  152. package/dist/bridges/equations/be-45-tcc.js +10 -22
  153. package/dist/bridges/equations/be-45-tcc.js.map +1 -1
  154. package/dist/bridges/equations/be-46-multiverse-measure.d.ts +7 -1
  155. package/dist/bridges/equations/be-46-multiverse-measure.d.ts.map +1 -1
  156. package/dist/bridges/equations/be-46-multiverse-measure.js +9 -19
  157. package/dist/bridges/equations/be-46-multiverse-measure.js.map +1 -1
  158. package/dist/bridges/equations/be-47-bbn-dark-sector.d.ts +7 -1
  159. package/dist/bridges/equations/be-47-bbn-dark-sector.d.ts.map +1 -1
  160. package/dist/bridges/equations/be-47-bbn-dark-sector.js +14 -16
  161. package/dist/bridges/equations/be-47-bbn-dark-sector.js.map +1 -1
  162. package/dist/bridges/equations/be-48-grw-localization.d.ts +7 -1
  163. package/dist/bridges/equations/be-48-grw-localization.d.ts.map +1 -1
  164. package/dist/bridges/equations/be-48-grw-localization.js +15 -20
  165. package/dist/bridges/equations/be-48-grw-localization.js.map +1 -1
  166. package/dist/bridges/equations/be-49-quantum-darwinism.d.ts +7 -1
  167. package/dist/bridges/equations/be-49-quantum-darwinism.d.ts.map +1 -1
  168. package/dist/bridges/equations/be-49-quantum-darwinism.js +10 -22
  169. package/dist/bridges/equations/be-49-quantum-darwinism.js.map +1 -1
  170. package/dist/bridges/equations/be-50-wheeler-feynman.d.ts +42 -12
  171. package/dist/bridges/equations/be-50-wheeler-feynman.d.ts.map +1 -1
  172. package/dist/bridges/equations/be-50-wheeler-feynman.js +84 -20
  173. package/dist/bridges/equations/be-50-wheeler-feynman.js.map +1 -1
  174. package/dist/bridges/equations/be-53-yang-mills-beta.d.ts +158 -0
  175. package/dist/bridges/equations/be-53-yang-mills-beta.d.ts.map +1 -0
  176. package/dist/bridges/equations/be-53-yang-mills-beta.js +175 -0
  177. package/dist/bridges/equations/be-53-yang-mills-beta.js.map +1 -0
  178. package/dist/bridges/equations/be-54-randall-sundrum-brane.d.ts +117 -0
  179. package/dist/bridges/equations/be-54-randall-sundrum-brane.d.ts.map +1 -0
  180. package/dist/bridges/equations/be-54-randall-sundrum-brane.js +213 -0
  181. package/dist/bridges/equations/be-54-randall-sundrum-brane.js.map +1 -0
  182. package/dist/bridges/gravitational-lensing.d.ts +13 -2
  183. package/dist/bridges/gravitational-lensing.d.ts.map +1 -1
  184. package/dist/bridges/gravitational-lensing.js +17 -6
  185. package/dist/bridges/gravitational-lensing.js.map +1 -1
  186. package/dist/bridges/index.d.ts +40 -1
  187. package/dist/bridges/index.d.ts.map +1 -1
  188. package/dist/bridges/index.js +130 -48
  189. package/dist/bridges/index.js.map +1 -1
  190. package/dist/bridges/perihelion-precession-labeled.d.ts +46 -0
  191. package/dist/bridges/perihelion-precession-labeled.d.ts.map +1 -0
  192. package/dist/bridges/perihelion-precession-labeled.js +54 -0
  193. package/dist/bridges/perihelion-precession-labeled.js.map +1 -0
  194. package/dist/bridges/perihelion-precession.d.ts +18 -3
  195. package/dist/bridges/perihelion-precession.d.ts.map +1 -1
  196. package/dist/bridges/perihelion-precession.js +22 -8
  197. package/dist/bridges/perihelion-precession.js.map +1 -1
  198. package/dist/core/axes-registry.d.ts +67 -0
  199. package/dist/core/axes-registry.d.ts.map +1 -0
  200. package/dist/core/axes-registry.js +75 -0
  201. package/dist/core/axes-registry.js.map +1 -0
  202. package/dist/core/cell.d.ts +176 -0
  203. package/dist/core/cell.d.ts.map +1 -0
  204. package/dist/core/cell.js +166 -0
  205. package/dist/core/cell.js.map +1 -0
  206. package/dist/core/constants.d.ts +50 -0
  207. package/dist/core/constants.d.ts.map +1 -0
  208. package/dist/core/constants.js +50 -0
  209. package/dist/core/constants.js.map +1 -0
  210. package/dist/core/flux-rules.d.ts +176 -0
  211. package/dist/core/flux-rules.d.ts.map +1 -0
  212. package/dist/core/flux-rules.js +329 -0
  213. package/dist/core/flux-rules.js.map +1 -0
  214. package/dist/core/labeled-tensor.d.ts +143 -0
  215. package/dist/core/labeled-tensor.d.ts.map +1 -0
  216. package/dist/core/labeled-tensor.js +275 -0
  217. package/dist/core/labeled-tensor.js.map +1 -0
  218. package/dist/core/regime-registry.d.ts +169 -0
  219. package/dist/core/regime-registry.d.ts.map +1 -0
  220. package/dist/core/regime-registry.js +174 -0
  221. package/dist/core/regime-registry.js.map +1 -0
  222. package/dist/core/regime-rule-install.d.ts +26 -0
  223. package/dist/core/regime-rule-install.d.ts.map +1 -0
  224. package/dist/core/regime-rule-install.js +90 -0
  225. package/dist/core/regime-rule-install.js.map +1 -0
  226. package/dist/core/regimes-builtins.d.ts +22 -0
  227. package/dist/core/regimes-builtins.d.ts.map +1 -0
  228. package/dist/core/regimes-builtins.js +96 -0
  229. package/dist/core/regimes-builtins.js.map +1 -0
  230. package/dist/core/tensor.d.ts +112 -0
  231. package/dist/core/tensor.d.ts.map +1 -1
  232. package/dist/core/tensor.js +366 -0
  233. package/dist/core/tensor.js.map +1 -1
  234. package/dist/core/types.d.ts +7 -2
  235. package/dist/core/types.d.ts.map +1 -1
  236. package/dist/core/types.js.map +1 -1
  237. package/dist/core/universal-index.d.ts +97 -0
  238. package/dist/core/universal-index.d.ts.map +1 -0
  239. package/dist/core/universal-index.js +70 -0
  240. package/dist/core/universal-index.js.map +1 -0
  241. package/dist/diff/bridge-gradient.d.ts +94 -0
  242. package/dist/diff/bridge-gradient.d.ts.map +1 -0
  243. package/dist/diff/bridge-gradient.js +83 -0
  244. package/dist/diff/bridge-gradient.js.map +1 -0
  245. package/dist/diff/bridge-specs.d.ts +68 -0
  246. package/dist/diff/bridge-specs.d.ts.map +1 -0
  247. package/dist/diff/bridge-specs.js +96 -0
  248. package/dist/diff/bridge-specs.js.map +1 -0
  249. package/dist/dimensional/bridge-check.d.ts.map +1 -1
  250. package/dist/dimensional/bridge-check.js +8 -0
  251. package/dist/dimensional/bridge-check.js.map +1 -1
  252. package/dist/dimensional/connection-validators.d.ts +13 -6
  253. package/dist/dimensional/connection-validators.d.ts.map +1 -1
  254. package/dist/dimensional/connection-validators.js +1 -1
  255. package/dist/dimensional/connection-validators.js.map +1 -1
  256. package/dist/dimensional/curvature-composite.d.ts +90 -0
  257. package/dist/dimensional/curvature-composite.d.ts.map +1 -0
  258. package/dist/dimensional/curvature-composite.js +57 -0
  259. package/dist/dimensional/curvature-composite.js.map +1 -0
  260. package/dist/dimensional/curvature-invariants.d.ts +90 -0
  261. package/dist/dimensional/curvature-invariants.d.ts.map +1 -0
  262. package/dist/dimensional/curvature-invariants.js +64 -0
  263. package/dist/dimensional/curvature-invariants.js.map +1 -0
  264. package/dist/dimensional/curvature.d.ts +82 -41
  265. package/dist/dimensional/curvature.d.ts.map +1 -1
  266. package/dist/dimensional/curvature.js +19 -11
  267. package/dist/dimensional/curvature.js.map +1 -1
  268. package/dist/dimensional/einstein-equation.d.ts +126 -0
  269. package/dist/dimensional/einstein-equation.d.ts.map +1 -0
  270. package/dist/dimensional/einstein-equation.js +122 -0
  271. package/dist/dimensional/einstein-equation.js.map +1 -0
  272. package/dist/dimensional/field-equation-helpers.d.ts +82 -0
  273. package/dist/dimensional/field-equation-helpers.d.ts.map +1 -0
  274. package/dist/dimensional/field-equation-helpers.js +123 -0
  275. package/dist/dimensional/field-equation-helpers.js.map +1 -0
  276. package/dist/dimensional/friedmann-equation.d.ts +148 -0
  277. package/dist/dimensional/friedmann-equation.d.ts.map +1 -0
  278. package/dist/dimensional/friedmann-equation.js +150 -0
  279. package/dist/dimensional/friedmann-equation.js.map +1 -0
  280. package/dist/dimensional/gauge-field.d.ts +182 -0
  281. package/dist/dimensional/gauge-field.d.ts.map +1 -0
  282. package/dist/dimensional/gauge-field.js +134 -0
  283. package/dist/dimensional/gauge-field.js.map +1 -0
  284. package/dist/dimensional/killing-validators.d.ts +94 -0
  285. package/dist/dimensional/killing-validators.d.ts.map +1 -0
  286. package/dist/dimensional/killing-validators.js +66 -0
  287. package/dist/dimensional/killing-validators.js.map +1 -0
  288. package/dist/dimensional/klein-gordon-equation.d.ts +113 -0
  289. package/dist/dimensional/klein-gordon-equation.d.ts.map +1 -0
  290. package/dist/dimensional/klein-gordon-equation.js +98 -0
  291. package/dist/dimensional/klein-gordon-equation.js.map +1 -0
  292. package/dist/dimensional/rg-flow.d.ts +156 -0
  293. package/dist/dimensional/rg-flow.d.ts.map +1 -0
  294. package/dist/dimensional/rg-flow.js +150 -0
  295. package/dist/dimensional/rg-flow.js.map +1 -0
  296. package/dist/dimensional/stress-energy-validators.d.ts +74 -0
  297. package/dist/dimensional/stress-energy-validators.d.ts.map +1 -0
  298. package/dist/dimensional/stress-energy-validators.js +47 -0
  299. package/dist/dimensional/stress-energy-validators.js.map +1 -0
  300. package/dist/dimensional/tensor-trace.d.ts +128 -0
  301. package/dist/dimensional/tensor-trace.d.ts.map +1 -0
  302. package/dist/dimensional/tensor-trace.js +95 -0
  303. package/dist/dimensional/tensor-trace.js.map +1 -0
  304. package/dist/dimensional/tensor.d.ts +6 -8
  305. package/dist/dimensional/tensor.d.ts.map +1 -1
  306. package/dist/dimensional/tensor.js +3 -1
  307. package/dist/dimensional/tensor.js.map +1 -1
  308. package/dist/dimensional/validator-registry.d.ts +90 -0
  309. package/dist/dimensional/validator-registry.d.ts.map +1 -0
  310. package/dist/dimensional/validator-registry.js +131 -0
  311. package/dist/dimensional/validator-registry.js.map +1 -0
  312. package/dist/dimensional/validator.d.ts +12 -2
  313. package/dist/dimensional/validator.d.ts.map +1 -1
  314. package/dist/dimensional/validator.js +60 -75
  315. package/dist/dimensional/validator.js.map +1 -1
  316. package/dist/dimensional/weyl-validators.d.ts +84 -0
  317. package/dist/dimensional/weyl-validators.d.ts.map +1 -0
  318. package/dist/dimensional/weyl-validators.js +84 -0
  319. package/dist/dimensional/weyl-validators.js.map +1 -0
  320. package/dist/index.d.ts +38 -0
  321. package/dist/index.d.ts.map +1 -1
  322. package/dist/index.js +45 -0
  323. package/dist/index.js.map +1 -1
  324. package/dist/numerical/be37-covariant-eikonal.d.ts +37 -2
  325. package/dist/numerical/be37-covariant-eikonal.d.ts.map +1 -1
  326. package/dist/numerical/be37-covariant-eikonal.js +51 -14
  327. package/dist/numerical/be37-covariant-eikonal.js.map +1 -1
  328. package/dist/numerical/christoffel-flat.d.ts +49 -0
  329. package/dist/numerical/christoffel-flat.d.ts.map +1 -0
  330. package/dist/numerical/christoffel-flat.js +86 -0
  331. package/dist/numerical/christoffel-flat.js.map +1 -0
  332. package/dist/numerical/curvature-lowering-helpers.d.ts +76 -57
  333. package/dist/numerical/curvature-lowering-helpers.d.ts.map +1 -1
  334. package/dist/numerical/curvature-lowering-helpers.js +203 -64
  335. package/dist/numerical/curvature-lowering-helpers.js.map +1 -1
  336. package/dist/numerical/derivative-lowering.d.ts +67 -0
  337. package/dist/numerical/derivative-lowering.d.ts.map +1 -0
  338. package/dist/numerical/derivative-lowering.js +243 -0
  339. package/dist/numerical/derivative-lowering.js.map +1 -0
  340. package/dist/numerical/einstein-equation.d.ts +106 -0
  341. package/dist/numerical/einstein-equation.d.ts.map +1 -0
  342. package/dist/numerical/einstein-equation.js +172 -0
  343. package/dist/numerical/einstein-equation.js.map +1 -0
  344. package/dist/numerical/engine-registry.js +4 -4
  345. package/dist/numerical/engine-registry.js.map +1 -1
  346. package/dist/numerical/geodesic-integrator.d.ts +7 -4
  347. package/dist/numerical/geodesic-integrator.d.ts.map +1 -1
  348. package/dist/numerical/geodesic-integrator.js +5 -1
  349. package/dist/numerical/geodesic-integrator.js.map +1 -1
  350. package/dist/numerical/gl4-integrator.d.ts +57 -9
  351. package/dist/numerical/gl4-integrator.d.ts.map +1 -1
  352. package/dist/numerical/gl4-integrator.js +63 -16
  353. package/dist/numerical/gl4-integrator.js.map +1 -1
  354. package/dist/numerical/killing.d.ts +157 -0
  355. package/dist/numerical/killing.d.ts.map +1 -0
  356. package/dist/numerical/killing.js +242 -0
  357. package/dist/numerical/killing.js.map +1 -0
  358. package/dist/numerical/kretschmann.d.ts +62 -0
  359. package/dist/numerical/kretschmann.d.ts.map +1 -0
  360. package/dist/numerical/kretschmann.js +88 -0
  361. package/dist/numerical/kretschmann.js.map +1 -0
  362. package/dist/numerical/lowering-utils.d.ts +47 -0
  363. package/dist/numerical/lowering-utils.d.ts.map +1 -0
  364. package/dist/numerical/lowering-utils.js +64 -0
  365. package/dist/numerical/lowering-utils.js.map +1 -0
  366. package/dist/numerical/lowering.d.ts +1 -29
  367. package/dist/numerical/lowering.d.ts.map +1 -1
  368. package/dist/numerical/lowering.js +226 -415
  369. package/dist/numerical/lowering.js.map +1 -1
  370. package/dist/numerical/mathts-engine.js +8 -8
  371. package/dist/numerical/mathts-engine.js.map +1 -1
  372. package/dist/numerical/metric-inverse.d.ts.map +1 -1
  373. package/dist/numerical/metric-inverse.js +28 -0
  374. package/dist/numerical/metric-inverse.js.map +1 -1
  375. package/dist/numerical/null-ic.d.ts +40 -0
  376. package/dist/numerical/null-ic.d.ts.map +1 -0
  377. package/dist/numerical/null-ic.js +50 -0
  378. package/dist/numerical/null-ic.js.map +1 -0
  379. package/dist/numerical/null-ray-integrator.d.ts +3 -2
  380. package/dist/numerical/null-ray-integrator.d.ts.map +1 -1
  381. package/dist/numerical/null-ray-integrator.js +6 -3
  382. package/dist/numerical/null-ray-integrator.js.map +1 -1
  383. package/dist/numerical/painleve-gullstrand-metric.d.ts +74 -0
  384. package/dist/numerical/painleve-gullstrand-metric.d.ts.map +1 -0
  385. package/dist/numerical/painleve-gullstrand-metric.js +121 -0
  386. package/dist/numerical/painleve-gullstrand-metric.js.map +1 -0
  387. package/dist/numerical/pderiv.d.ts +35 -3
  388. package/dist/numerical/pderiv.d.ts.map +1 -1
  389. package/dist/numerical/pderiv.js +47 -12
  390. package/dist/numerical/pderiv.js.map +1 -1
  391. package/dist/numerical/perihelion-finder.d.ts +57 -0
  392. package/dist/numerical/perihelion-finder.d.ts.map +1 -1
  393. package/dist/numerical/perihelion-finder.js +57 -0
  394. package/dist/numerical/perihelion-finder.js.map +1 -1
  395. package/dist/numerical/tensor-engine.d.ts +2 -2
  396. package/dist/numerical/tensor-engine.d.ts.map +1 -1
  397. package/dist/numerical/weyl-lowering.d.ts +60 -0
  398. package/dist/numerical/weyl-lowering.d.ts.map +1 -0
  399. package/dist/numerical/weyl-lowering.js +111 -0
  400. package/dist/numerical/weyl-lowering.js.map +1 -0
  401. package/package.json +9 -7
@@ -10,13 +10,23 @@
10
10
  *
11
11
  * @module numerical/lowering
12
12
  */
13
- import { validate } from '../dimensional/validator.js';
14
13
  import { computeContraction, validateTensorSymbol } from '../dimensional/tensor.js';
15
- import { pderivGrid, pderivNumericalFn, pderivSymbolic } from './pderiv.js';
16
14
  import { validateMetricTensor, validateKroneckerDelta, validatePartialDerivative, } from '../dimensional/metric-validators.js';
17
15
  import { NumericalBackendError } from './errors.js';
18
- import { zeroTensor, zeroTensorLike, flatToNested, flattenNA, tensorAdd, tensorAddScaled, computeChristoffelTensor, contractChristoffelWithOperand, getMetricDerivFlat, } from './connection-lowering-helpers.js';
19
- import { christoffelAt, dGammaAt, buildRiemann, bianchiResidualAt, } from './curvature-lowering-helpers.js';
16
+ import { christoffelAt, dGammaAt, buildRiemann, contractRiemannJS,
17
+ // v0.6.1 Phase 2: the bianchi-residual + weyl-tensor arms moved into
18
+ // these two helpers (full FD pipeline + result-wrap).
19
+ lowerBianchiResidual, lowerWeylTensor, } from './curvature-lowering-helpers.js';
20
+ // v0.7 follow-up to v0.6.1's LOC-target miss: the four private helpers
21
+ // (isMetricTensorNode, dimensionOf, requireValue, flattenNestedArray)
22
+ // live in lowering-utils.ts so the new derivative-lowering.ts can
23
+ // share them without a forward-import cycle.
24
+ import { dimensionOf, requireValue, flattenNestedArray, } from './lowering-utils.js';
25
+ // v0.7 follow-up: tensor-partial-derivative + covariant-derivative
26
+ // case arms extracted (was lines 523-820, ~298 LOC). The recursive
27
+ // lowerNode call is threaded as a thunk to keep the module graph
28
+ // acyclic.
29
+ import { lowerTensorPartialDerivative, lowerCovariantDerivative, } from './derivative-lowering.js';
20
30
  function isContractable(node) {
21
31
  return node.kind === 'tensor-symbol'
22
32
  || node.kind === 'metric-tensor'
@@ -39,26 +49,6 @@ function operandIndices(node) {
39
49
  }
40
50
  return node.indices;
41
51
  }
42
- function dimensionOf(inputs) {
43
- return inputs.dimension ?? 4;
44
- }
45
- /** Look up a named tensor's concrete value, or throw. */
46
- function requireValue(name, inputs) {
47
- const v = inputs.tensors.get(name);
48
- if (v === undefined) {
49
- throw new NumericalBackendError(`lowering: no value supplied for "${name}" in inputs.tensors`);
50
- }
51
- return v;
52
- }
53
- /** Flatten a NestedArray to a plain number[] and check expected size.
54
- * Delegates to the canonical flattenNA() from connection-lowering-helpers. */
55
- function flattenNestedArray(data, expectedSize) {
56
- const out = flattenNA(data);
57
- if (out.length !== expectedSize) {
58
- throw new NumericalBackendError(`lowering: flattenNestedArray: got ${out.length} elements, expected ${expectedSize}`);
59
- }
60
- return out;
61
- }
62
52
  /**
63
53
  * Build the EinsumSpec for a flat tensor-product.
64
54
  *
@@ -69,9 +59,10 @@ function flattenNestedArray(data, expectedSize) {
69
59
  * labels to their (operand, axis) sites. There is exactly one
70
60
  * contraction-decision implementation in the codebase.
71
61
  *
72
- * @internal cross-module/test use only; not part of the consumer surface.
62
+ * v0.6.1: dropped export was @internal-tagged with no external consumer.
63
+ * `lowerTensorProduct` (this file) is the only call site.
73
64
  */
74
- export function buildEinsumSpec(operands, contractionPairs, freeIndices) {
65
+ function buildEinsumSpec(operands, contractionPairs, freeIndices) {
75
66
  // Map every label to its (operand, axis) sites — via operandIndices() so a
76
67
  // tensor-partial-derivative operand contributes its [...of.indices, wrtIndex]
77
68
  // effective axes.
@@ -120,344 +111,19 @@ function lowerContractable(node, inputs, engine) {
120
111
  const shape = node.indices.map(() => N);
121
112
  return engine.fromNested(requireValue(node.name, inputs), shape);
122
113
  }
123
- /** Lower a validated ExprNode to an EngineTensor.
124
- * @internal cross-module/test use only; not part of the consumer surface. */
125
- export function lowerNode(node, inputs, engine) {
114
+ /**
115
+ * Dispatcher for the six curvature-composite AST kinds.
116
+ *
117
+ * v0.6.0 Task 3.10e: extracted from `lowerNode`'s switch so all curvature
118
+ * lowering logic lives in one named helper. `CURVATURE_KIND_REGISTRY[node.kind]`
119
+ * supplies the per-kind shape/dim spec; the actual numerical paths are
120
+ * preserved verbatim from the prior per-kind arms — no logic changes.
121
+ *
122
+ * Called from `lowerNode` for all `CurvatureKind` discriminants.
123
+ * @internal
124
+ */
125
+ function lowerCurvature(node, inputs, engine) {
126
126
  switch (node.kind) {
127
- case 'symbol':
128
- return engine.fromNested(requireValue(node.name, inputs), []);
129
- case 'tensor-symbol':
130
- case 'metric-tensor':
131
- case 'kronecker-delta':
132
- return lowerContractable(node, inputs, engine);
133
- case 'op': {
134
- if (node.op === '+' || node.op === '-') {
135
- if (node.args.length === 0)
136
- return engine.fromNested(0, []);
137
- let acc = lowerNode(node.args[0], inputs, engine);
138
- for (let i = 1; i < node.args.length; i++) {
139
- const next = lowerNode(node.args[i], inputs, engine);
140
- acc = node.op === '+' ? engine.add(acc, next) : engine.sub(acc, next);
141
- }
142
- return acc;
143
- }
144
- // '*' / '/' / '^' are scalar-only. Guard arity so an unvalidated AST
145
- // surfaces a clean NumericalBackendError instead of a raw TypeError
146
- // (zero-operand '/') or a silent NaN (wrong-arity '^'). The '*' case
147
- // with zero args is already fine — reduce(..., 1) returns 1.
148
- if (node.op === '/' && node.args.length === 0) {
149
- throw new NumericalBackendError("lowering: op '/' requires at least one operand");
150
- }
151
- if (node.op === '^' && node.args.length !== 2) {
152
- throw new NumericalBackendError(`lowering: op '^' requires exactly 2 operands (base, exponent), got ${node.args.length}`);
153
- }
154
- // '*' / '/' / '^' are scalar-only (the validator rejects tensor
155
- // operands). Lower each to rank-0, do the arithmetic in JS, lift back.
156
- const scalars = node.args.map((a) => {
157
- const t = lowerNode(a, inputs, engine);
158
- if (t.shape.length !== 0) {
159
- throw new NumericalBackendError(`lowering: op '${node.op}' got a rank-${t.shape.length} operand — scalar ops require rank-0`);
160
- }
161
- return engine.toNested(t);
162
- });
163
- let value;
164
- if (node.op === '*')
165
- value = scalars.reduce((a, b) => a * b, 1);
166
- else if (node.op === '/')
167
- value = scalars.reduce((a, b) => a / b);
168
- else
169
- value = Math.pow(scalars[0], scalars[1]); // '^'
170
- return engine.fromNested(value, []);
171
- }
172
- case 'tensor-product': {
173
- for (const arg of node.args) {
174
- if (arg.kind === 'tensor-product') {
175
- throw new NumericalBackendError('lowering: nested tensor-product numerical evaluation is not supported in v0.3.5 — '
176
- + 'flatten the contraction into a single product');
177
- }
178
- }
179
- // Contractable operands (tensor-symbol / metric-tensor / kronecker-delta
180
- // / tensor-partial-derivative) participate in the einsum; everything
181
- // else must be a rank-0 scalar factor.
182
- const operands = node.args.filter(isContractable);
183
- const scalarArgs = node.args.filter((a) => !isContractable(a));
184
- // computeContraction is the single authority on WHICH indices contract
185
- // (variance-aware, implicit-metric rule). See buildEinsumSpec JSDoc.
186
- // The recursive validateContractionChild resolves tensor-partial-derivative
187
- // operands via validatePartialDerivative.
188
- function validateContractionChild(child) {
189
- if (child.kind === 'tensor-symbol')
190
- return validateTensorSymbol(child);
191
- if (child.kind === 'metric-tensor')
192
- return validateMetricTensor(child);
193
- if (child.kind === 'kronecker-delta')
194
- return validateKroneckerDelta(child);
195
- if (child.kind === 'tensor-partial-derivative') {
196
- const r = validatePartialDerivative(child, (g) => validateContractionChild(g));
197
- return { dim: r.dim, freeIndices: r.freeIndices };
198
- }
199
- throw new NumericalBackendError(`lowering: unexpected operand '${child.kind}' in tensor-product einsum`);
200
- }
201
- const { contractionPairs, freeIndices } = computeContraction(operands, validateContractionChild);
202
- const spec = buildEinsumSpec(operands, contractionPairs, freeIndices);
203
- const operandTensors = operands.map((n) => lowerContractable(n, inputs, engine));
204
- let result = engine.einsum(spec, ...operandTensors);
205
- // Scalar operands multiply the whole contraction.
206
- for (const s of scalarArgs) {
207
- const st = lowerNode(s, inputs, engine);
208
- if (st.shape.length !== 0) {
209
- throw new NumericalBackendError('lowering: non-scalar non-contractable operand in tensor-product');
210
- }
211
- result = engine.scale(result, engine.toNested(st));
212
- }
213
- return result;
214
- }
215
- case 'tensor-partial-derivative': {
216
- // v0.3.5/v0.4.0 scope: `of` is a tensor-symbol or metric-tensor.
217
- // ∂_μ(of) adds the wrtIndex as a trailing axis — the result shape is
218
- // [...ofShape, N], NOT ofShape. (For BE-37, `of` = the scalar S is
219
- // rank-0, so ∂_μ S is the rank-1 wave covector k_μ, shape [N].)
220
- const of = node.of;
221
- // v0.4.0 extension: metric-tensor pderiv dispatch.
222
- if (of.kind === 'metric-tensor') {
223
- const mNode = of;
224
- const strategy = mNode.derivativeStrategy ?? 'computed';
225
- const N = dimensionOf(inputs);
226
- const coordLabel = node.wrtIndex.label;
227
- const ofShape = mNode.indices.map(() => N);
228
- const resultShape = [...ofShape, N];
229
- if (strategy === 'zero') {
230
- // ∂g = 0 everywhere (constant/flat metric).
231
- return zeroTensor(resultShape, engine);
232
- }
233
- if (strategy === 'supplied') {
234
- // Look up the N slices ∂_mu g for mu=0..N-1 and stack them as the
235
- // trailing axis. Key format: `${metricName}/${coordLabel}_${mu}`.
236
- // Result shape: [...ofShape, N] = [N, N, N] for a rank-2 metric.
237
- // Build as a flat array then convert to nested for engine.fromNested().
238
- const size = resultShape.reduce((a, b) => a * b, 1);
239
- const flat = new Array(size).fill(0);
240
- // ofShape = [N, N], resultShape = [N, N, N]
241
- // flat[i*N*N + j*N + mu] = (∂_mu g)[i][j]
242
- for (let mu = 0; mu < N; mu++) {
243
- const key = `${mNode.name}/${coordLabel}_${mu}`;
244
- const slice = inputs.metricDerivatives?.get(key);
245
- if (slice === undefined) {
246
- throw new NumericalBackendError(`lowering: metric-tensor pderiv with strategy='supplied': ` +
247
- `no metricDerivatives entry for "${key}"`);
248
- }
249
- // Flatten the slice (shape [N,N]) and write into flat at stride N (last axis)
250
- const flatSlice = flattenNestedArray(slice, N * N);
251
- for (let ij = 0; ij < N * N; ij++) {
252
- flat[ij * N + mu] = flatSlice[ij];
253
- }
254
- }
255
- return engine.fromNested(flatToNested(flat, resultShape), resultShape);
256
- }
257
- // strategy === 'computed': treat as zero for constant-tensor metrics
258
- // (the raw metric supplied via inputs.tensors has no coordinate dependence).
259
- return zeroTensor(resultShape, engine);
260
- }
261
- if (of.kind !== 'tensor-symbol') {
262
- throw new NumericalBackendError(`lowering: tensor-partial-derivative numerical eval requires a tensor-symbol `
263
- + `or metric-tensor 'of' operand in v0.3.5/v0.4.0 — got '${of.kind}'`);
264
- }
265
- const sym = of;
266
- const form = sym.numericalForm ?? 'symbolic';
267
- const coordLabel = node.wrtIndex.label;
268
- const N = dimensionOf(inputs);
269
- const ofShape = sym.indices.map(() => N);
270
- const resultShape = [...ofShape, N];
271
- if (form === 'symbolic') {
272
- // pderivSymbolic returns the caller-supplied full ∂_μ(of) tensor,
273
- // which must already be of shape [...ofShape, N].
274
- const d = pderivSymbolic(sym.name, coordLabel, inputs.derivatives ?? new Map());
275
- return engine.fromNested(d, resultShape);
276
- }
277
- if (form === 'numerical-fn') {
278
- // v0.3.5: 'numerical-fn' lowering is scoped to a rank-0 `of` (scalar
279
- // field). ∂_μ ranges over all N coordinate axes — stack the N
280
- // single-axis derivatives into the rank-1 result. Higher-rank fields
281
- // under 'numerical-fn' are a v0.4.0 concern.
282
- if (ofShape.length !== 0) {
283
- throw new NumericalBackendError(`lowering: 'numerical-fn' pderiv lowering supports a rank-0 'of' in v0.3.5; `
284
- + `"${sym.name}" is rank ${ofShape.length}`);
285
- }
286
- const fn = inputs.fields?.get(sym.name);
287
- if (!fn) {
288
- throw new NumericalBackendError(`lowering: 'numerical-fn' tensor-symbol "${sym.name}" has no field fn in inputs.fields`);
289
- }
290
- const coordValues = inputs.coords ? [...inputs.coords.values()] : [];
291
- const components = [];
292
- for (let axis = 0; axis < N; axis++) {
293
- components.push(pderivNumericalFn(fn, coordValues, axis));
294
- }
295
- return engine.fromNested(components, [N]);
296
- }
297
- // form === 'grid': the GridField is the field sampled over space, and
298
- // pderivGrid returns the derivative field sampled on that same grid —
299
- // result shape is grid.shape. This is a distinct semantic from
300
- // symbolic/numerical-fn (a sampled derivative field, not a single
301
- // tensor), kept as the v0.5.0 BSSN forward-compat path. v0.3.5 has no
302
- // release test driving 'grid' through lowering; pderivGrid itself is
303
- // unit-tested in Task 10's pderiv.test.ts.
304
- const grid = inputs.grids?.get(sym.name);
305
- if (!grid) {
306
- throw new NumericalBackendError(`lowering: 'grid' tensor-symbol "${sym.name}" has no GridField in inputs.grids`);
307
- }
308
- const gridAxis = inputs.coords ? [...inputs.coords.keys()].indexOf(coordLabel) : 0;
309
- const flat = pderivGrid(grid, gridAxis < 0 ? 0 : gridAxis);
310
- return engine.fromNested(flat.length === 1 ? flat[0] : flat, grid.shape);
311
- }
312
- case 'covariant-derivative': {
313
- // S2(a) fix: `of.freeIndices` does NOT exist on the raw ExprNode.
314
- // Re-validate the `of` subtree to obtain its free-index structure.
315
- const covNode = node;
316
- const ofExpr = covNode.of;
317
- // TS-2 runtime guard: `covNode.of` is typed as `unknown` (module-cycle
318
- // prevents ExprNode import in connection-validators.ts). The cast above
319
- // is unchecked — a malformed AST bypassing validate() would produce a
320
- // cryptic TypeError at `ofExpr.kind` below. Throw a clear message now.
321
- if (typeof ofExpr.kind !== 'string') {
322
- throw new NumericalBackendError(`lowering: CovariantDerivativeNode.of must have a string 'kind' field ` +
323
- `(got ${JSON.stringify(ofExpr.kind)}). ` +
324
- `Always call validate() before evaluateNumericalRaw().`);
325
- }
326
- const ofValidation = validate(ofExpr);
327
- // Build ordered list of free indices: [{label, variance}].
328
- // Iterate of.indices (NOT validation.freeIndices Map) — declaration order IS
329
- // the axis layout. For tensor-symbol and metric-tensor, of.indices is the
330
- // canonical axis order; the freeIndices Map insertion order is also
331
- // of.indices order (validateTensorSymbol iterates node.indices), but relying
332
- // on that is an undocumented invariant. Iterating of.indices directly makes
333
- // the axis ordering guarantee explicit and safe for future of-kinds.
334
- const ofFreeIndices = [];
335
- const ofIndices = ofExpr.indices;
336
- if (ofIndices) {
337
- // tensor-symbol / metric-tensor: iterate the declared indices in order.
338
- // Each index is either free (present in ofValidation.freeIndices) or
339
- // contracted (absent — skip). In practice, of.indices for a simple
340
- // tensor-symbol or metric-tensor has no contracted indices, but we
341
- // guard with the Map lookup for safety.
342
- for (const idx of ofIndices) {
343
- const counts = ofValidation.freeIndices.get(idx.label);
344
- if (counts === undefined)
345
- continue; // contracted — not a free axis
346
- ofFreeIndices.push({
347
- label: idx.label,
348
- variance: idx.variance,
349
- pos: ofFreeIndices.length,
350
- });
351
- }
352
- }
353
- else {
354
- // Fallback for future of-kinds without .indices (e.g. tensor-product).
355
- // Map iteration order is insertion order — a best-effort axis ordering.
356
- let axisPos = 0;
357
- for (const [label, counts] of ofValidation.freeIndices) {
358
- for (let i = 0; i < counts.upper; i++) {
359
- ofFreeIndices.push({ label, variance: 'upper', pos: axisPos++ });
360
- }
361
- for (let i = 0; i < counts.lower; i++) {
362
- ofFreeIndices.push({ label, variance: 'lower', pos: axisPos++ });
363
- }
364
- }
365
- }
366
- // Lower the operand tensor.
367
- const ofTensor = lowerNode(ofExpr, inputs, engine);
368
- const N = dimensionOf(inputs);
369
- // TS-2 runtime guard: gLower must be a metric-tensor node (validated
370
- // upstream). A malformed AST bypassing validate() could reach here with
371
- // a wrong kind, causing a silent wrong-path execution.
372
- if (covNode.gLower.kind !== 'metric-tensor') {
373
- throw new NumericalBackendError(`lowering: CovariantDerivativeNode.gLower must be a metric-tensor node ` +
374
- `(got kind='${covNode.gLower.kind}')`);
375
- }
376
- const strategy = covNode.gLower.derivativeStrategy ?? 'computed';
377
- // S2(b): strategy='zero' → flat space, Γ=0, ∇_μ T = ∂_μ T.
378
- // For constant tensors (like a flat metric), ∂_μ T = 0, so result is all zeros.
379
- // We return a zero tensor of shape [...ofShape, N] (wrt axis appended last).
380
- if (strategy === 'zero') {
381
- const outShape = [...ofTensor.shape, N];
382
- return zeroTensor(outShape, engine);
383
- }
384
- // v0.4.0 CRITICAL FIX (Finding #1): 'computed' on a raw-tensor metric means
385
- // constant metric → Γ = 0 → covariant-derivative = partial derivative only.
386
- // v0.5.0 will replace this with coordinate-grid finite-difference.
387
- // This early return MUST come before the Christoffel construction below,
388
- // because getMetricDerivFlat only accepts 'zero' | 'supplied'; if 'computed'
389
- // fell through, the type cast was silently wrong at runtime and the function
390
- // threw NumericalBackendError for every coordinate.
391
- //
392
- // Compute partial first so we can return it directly.
393
- // (partial is also needed by the 'supplied' path below, so we compute it
394
- // unconditionally and use the early return only for 'computed'.)
395
- //
396
- // UC-2 (v0.4.6): `of` is always tensor-symbol or metric-tensor at this
397
- // point. validateCovariantDerivative (connection-validators.ts) only
398
- // accepts those kinds for the 'of' field; any other kind fails dimensional
399
- // validation before evaluateNumerical reaches lowerNode. A covariant-
400
- // derivative with a scalar 'of' (ofFreeIndices.length === 0) already
401
- // returned at the early-return below. The old else-branch ("Scalar or
402
- // other: partial is zero") was therefore unreachable and is removed here;
403
- // replaced with an explicit throw to make the invariant visible if a
404
- // bypass-validate AST construction ever violates it.
405
- if (ofExpr.kind !== 'tensor-symbol' && ofExpr.kind !== 'metric-tensor') {
406
- throw new NumericalBackendError(`lowering: covariant-derivative 'of' must be tensor-symbol or metric-tensor ` +
407
- `(got '${ofExpr.kind}') — validated nodes cannot reach this point`);
408
- }
409
- const pdNode = {
410
- kind: 'tensor-partial-derivative',
411
- of: ofExpr,
412
- wrt: covNode.wrt,
413
- wrtIndex: covNode.wrtIndex,
414
- };
415
- const partial = lowerNode(pdNode, inputs, engine);
416
- // v0.4.0 spec: 'computed' on a raw-tensor metric = constant metric → Γ = 0.
417
- // The covariant-derivative reduces to the ordinary partial derivative.
418
- // v0.5.0 will add coordinate-grid finite-difference here.
419
- if (strategy === 'computed') {
420
- return partial;
421
- }
422
- // S2(c) + S2(d): Build Christoffel Γ^α_{μν} from metric data and apply
423
- // the sign rule to all free indices of `of`:
424
- // ∇_μ T^α_β = ∂_μ T^α_β + Γ^α_{μλ} T^λ_β − Γ^λ_{μβ} T^α_λ
425
- //
426
- // If `of` has no free indices (scalar), no correction needed.
427
- if (ofFreeIndices.length === 0) {
428
- return partial;
429
- }
430
- // Get metric and inverse metric data.
431
- const gLowerNode = covNode.gLower;
432
- const gInverseNode = covNode.gInverse;
433
- const gInverseData = flattenNestedArray(requireValue(gInverseNode.name, inputs), N * N);
434
- // coordLabel for metricDerivatives keys (wrtIndex.label of the covariant derivative)
435
- const coordLabel = covNode.wrtIndex.label;
436
- // getMetricDeriv(mu): returns flat [N*N] of ∂_{mu} g
437
- const getMetricDeriv = (mu) => getMetricDerivFlat(gLowerNode.name, coordLabel, mu, 'supplied',
438
- // ^ strategy can only be 'supplied' here: 'zero' returned at line 457-459,
439
- // 'computed' returned at line 491-493, scalar 'of' returned at line 500-502.
440
- // Safe per audit UC-1: 'zero' strategy is short-circuited in earlier guard.
441
- N, inputs.metricDerivatives);
442
- // Compute Γ^α_{μν} from metric data.
443
- const GammaTensor = computeChristoffelTensor(gInverseData, getMetricDeriv, N, engine);
444
- const GammaFlat = flattenNestedArray(engine.toNested(GammaTensor), N * N * N);
445
- // Apply the Christoffel correction for each free index of `of`.
446
- // S2(d) sign rule: upper → +Γ, lower → −Γ.
447
- const ofFlat = flattenNestedArray(engine.toNested(ofTensor), ofTensor.shape.reduce((a, b) => a * b, 1));
448
- const ofShapeArr = [...ofTensor.shape];
449
- let correction = zeroTensorLike(partial, engine);
450
- for (const freeIdx of ofFreeIndices) {
451
- const term = contractChristoffelWithOperand(GammaFlat, ofFlat, ofShapeArr, freeIdx.pos, freeIdx.variance, N, engine);
452
- const sign = freeIdx.variance === 'upper' ? 1 : -1;
453
- correction = tensorAddScaled(correction, term, sign, engine);
454
- }
455
- return tensorAdd(partial, correction, engine);
456
- }
457
- case 'integral':
458
- case 'derivative':
459
- throw new NumericalBackendError(`lowering: '${node.kind}' is not numerically evaluated in v0.3.5 — `
460
- + 'use tensor-partial-derivative for differentiation');
461
127
  case 'ricci-tensor': {
462
128
  // v0.5.0 Task 7 — Ricci R_μν = R^λ_{μλν} (Carroll Eq. 3.91). Lowers
463
129
  // the embedded Riemann tensor via the 'riemann-tensor' case (so all
@@ -487,24 +153,16 @@ export function lowerNode(node, inputs, engine) {
487
153
  // composite node directly, no rewrite into a tensor-product.)
488
154
  const ricciNode = node;
489
155
  const N = dimensionOf(inputs);
490
- const innerR = lowerNode(ricciNode.riemann, inputs, engine);
156
+ // RiemannTensorNode is a member of ExprNode and CurvatureKind — cast is safe.
157
+ const innerR = lowerCurvature(ricciNode.riemann, inputs, engine);
491
158
  const flatR = flattenNestedArray(engine.toNested(innerR), N * N * N * N);
492
- // Contract R[λ][μ_out][λ][ν_out] → Ricci[μ_out][ν_out].
493
- // Flat index of R[a][b][c][d] (row-major, all axes size N):
494
- // a*N^3 + b*N^2 + c*N + d.
495
- const ricci2d = Array.from({ length: N }, () => new Array(N).fill(0));
496
- const N2 = N * N;
497
- const N3 = N * N * N;
498
- for (let muOut = 0; muOut < N; muOut++) {
499
- for (let nuOut = 0; nuOut < N; nuOut++) {
500
- let sum = 0;
501
- for (let lam = 0; lam < N; lam++) {
502
- // R[lam][muOut][lam][nuOut]
503
- sum += flatR[lam * N3 + muOut * N2 + lam * N + nuOut];
504
- }
505
- ricci2d[muOut][nuOut] = sum;
506
- }
507
- }
159
+ // Contract R[λ][μ_out][λ][ν_out] → Ricci[μ_out][ν_out] via the shared
160
+ // `contractRiemannJS` helper (AS-1, v0.5.1). On R^ρ_{σμν} stored as
161
+ // R[ρ][σ][μ][ν], the Carroll Eq. 3.91 contraction is upperAxis=0 (ρ)
162
+ // against lowerAxis=2 (μ); free outputs are axes [1, 3] = (σ, ν).
163
+ const ricci2d = contractRiemannJS(flatR, N, {
164
+ upperAxis: 0, lowerAxis: 2, outAxes: [1, 3],
165
+ });
508
166
  return engine.fromNested(ricci2d, [N, N]);
509
167
  }
510
168
  case 'einstein-tensor': {
@@ -533,7 +191,7 @@ export function lowerNode(node, inputs, engine) {
533
191
  const ricciNodeInner = {
534
192
  kind: 'ricci-tensor', riemann: eNode.riemann,
535
193
  };
536
- const innerR = lowerNode(ricciNodeInner, inputs, engine);
194
+ const innerR = lowerCurvature(ricciNodeInner, inputs, engine);
537
195
  const Ric = engine.toNested(innerR);
538
196
  // Step 2: g_μν and g^μν from inputs.tensors (raw constant matrices at
539
197
  // the test coordinate point). Mirrors how ricci-tensor's de-Sitter
@@ -559,40 +217,9 @@ export function lowerNode(node, inputs, engine) {
559
217
  }
560
218
  case 'bianchi-residual': {
561
219
  // v0.5.0 Task 9 — Bianchi-identity residual B_{λμνρσ}.
562
- //
563
- // Approach 1 (full ∇, not raw ∂): cyclic sum
564
- // B_{λμνρσ} = ∇_λ R_{μνρσ} + ∇_μ R_{νλρσ} + ∇_ν R_{λμρσ}
565
- // where each ∇_λ R_{μνρσ} is computed with the four Christoffel-
566
- // correction terms (one per lower index of R). All FD/contraction
567
- // arithmetic happens in the helper module — this case just wires
568
- // x / metric closures from `inputs` to `bianchiResidualAt`.
569
- //
570
- // The result is a 5-deep nested array [N][N][N][N][N] with index order
571
- // B[λ][μ][ν][ρ][σ]. Returned as an EngineTensor of shape [N,N,N,N,N];
572
- // callers (typically bianchiResidual().evaluate) materialise via
573
- // engine.toNested.
574
- //
575
- // Walks the node directly — no AST rewrite into an op('+') of pderiv
576
- // products. Matches Task 6/7/8 walk-directly philosophy.
577
- const bNode = node;
578
- const rNode = bNode.riemann;
579
- const N = dimensionOf(inputs);
580
- // Coordinate value: same convention as the riemann-tensor case.
581
- const xCoordName = rNode.xCoord.name;
582
- const xRaw = requireValue(xCoordName, inputs);
583
- const x = flattenNestedArray(xRaw, N);
584
- // Coordinate-dependent metric closures.
585
- const gName = rNode.gLower.name;
586
- const gInvName = rNode.gInverse.name;
587
- const gFn = inputs.fields?.get(gName);
588
- const gInverseFn = inputs.fields?.get(gInvName);
589
- if (!gFn || !gInverseFn) {
590
- throw new NumericalBackendError(`lowering: bianchi-residual numerical evaluation requires coordinate-` +
591
- `dependent metric closures in inputs.fields for "${gName}" and "${gInvName}". ` +
592
- `Got fields=[${[...(inputs.fields?.keys() ?? [])].join(',')}].`);
593
- }
594
- const B = bianchiResidualAt(x, gFn, gInverseFn, N, engine);
595
- return engine.fromNested(B, [N, N, N, N, N]);
220
+ // Extracted into `lowerBianchiResidual` in v0.6.1 Phase 2; the body
221
+ // here is just the type-narrowed dispatch.
222
+ return lowerBianchiResidual(node, inputs, engine);
596
223
  }
597
224
  case 'riemann-tensor': {
598
225
  // v0.5.0 Task 6 (Phase 1c-ii). Walks the node directly (no AST rewrite
@@ -627,6 +254,190 @@ export function lowerNode(node, inputs, engine) {
627
254
  // Materialise back into an EngineTensor in [N,N,N,N] shape.
628
255
  return engine.fromNested(R, [N, N, N, N]);
629
256
  }
257
+ case 'weyl-tensor': {
258
+ // v0.6.0 Task 3.2 — Weyl C^ρ_{σμν}.
259
+ // Extracted into `lowerWeylTensor` in v0.6.1 Phase 2; the body here
260
+ // is just the type-narrowed dispatch.
261
+ return lowerWeylTensor(node, inputs, engine);
262
+ }
263
+ case 'kretschmann-scalar': {
264
+ // v0.6.0 Task 3.5/3.6 — KretschmannScalarNode: K = R_{ρσμν} R^{ρσμν}.
265
+ //
266
+ // The full lowering arm (Riemann→lower + computeKretschmann) is deferred
267
+ // to Task 3.7 where the Schwarzschild closed-form test pins it. Callers
268
+ // can invoke `computeKretschmann` directly with a sampled riemannLower
269
+ // array (see tests/numerical/kretschmann-schwarzschild.test.ts).
270
+ //
271
+ // Raises a descriptive error so callers get a clear signal instead of
272
+ // the generic 'unknown kind' exhaustiveness message.
273
+ void node;
274
+ throw new NumericalBackendError(`lowering: 'kretschmann-scalar' end-to-end lowering is not yet implemented ` +
275
+ `(Task 3.7). Use computeKretschmann() from src/numerical/kretschmann.ts ` +
276
+ `with a pre-computed riemannLower array and invertMetric().`);
277
+ }
278
+ default: {
279
+ const _exhaustive = node;
280
+ void _exhaustive;
281
+ throw new NumericalBackendError(`lowerCurvature: unhandled curvature kind ${JSON.stringify(node.kind)}`);
282
+ }
283
+ }
284
+ }
285
+ /** Lower a validated ExprNode to an EngineTensor.
286
+ * @internal — cross-module/test use only; not part of the consumer surface. */
287
+ export function lowerNode(node, inputs, engine) {
288
+ switch (node.kind) {
289
+ case 'symbol':
290
+ return engine.fromNested(requireValue(node.name, inputs), []);
291
+ case 'tensor-symbol':
292
+ case 'metric-tensor':
293
+ case 'kronecker-delta':
294
+ return lowerContractable(node, inputs, engine);
295
+ case 'op': {
296
+ if (node.op === '+' || node.op === '-') {
297
+ if (node.args.length === 0)
298
+ return engine.fromNested(0, []);
299
+ let acc = lowerNode(node.args[0], inputs, engine);
300
+ for (let i = 1; i < node.args.length; i++) {
301
+ const next = lowerNode(node.args[i], inputs, engine);
302
+ acc = node.op === '+' ? engine.add(acc, next) : engine.sub(acc, next);
303
+ }
304
+ return acc;
305
+ }
306
+ // '*' / '/' / '^' are scalar-only. Guard arity so an unvalidated AST
307
+ // surfaces a clean NumericalBackendError instead of a raw TypeError
308
+ // (zero-operand '/') or a silent NaN (wrong-arity '^'). The '*' case
309
+ // with zero args is already fine — reduce(..., 1) returns 1.
310
+ if (node.op === '/' && node.args.length === 0) {
311
+ throw new NumericalBackendError("lowering: op '/' requires at least one operand");
312
+ }
313
+ if (node.op === '^' && node.args.length !== 2) {
314
+ throw new NumericalBackendError(`lowering: op '^' requires exactly 2 operands (base, exponent), got ${node.args.length}`);
315
+ }
316
+ // '*' / '/' / '^' are scalar-only (the validator rejects tensor
317
+ // operands). Lower each to rank-0, do the arithmetic in JS, lift back.
318
+ const scalars = node.args.map((a) => {
319
+ const t = lowerNode(a, inputs, engine);
320
+ if (t.shape.length !== 0) {
321
+ throw new NumericalBackendError(`lowering: op '${node.op}' got a rank-${t.shape.length} operand — scalar ops require rank-0`);
322
+ }
323
+ return engine.toNested(t);
324
+ });
325
+ let value;
326
+ if (node.op === '*')
327
+ value = scalars.reduce((a, b) => a * b, 1);
328
+ else if (node.op === '/')
329
+ value = scalars.reduce((a, b) => a / b);
330
+ else
331
+ value = Math.pow(scalars[0], scalars[1]); // '^'
332
+ return engine.fromNested(value, []);
333
+ }
334
+ case 'tensor-product': {
335
+ for (const arg of node.args) {
336
+ if (arg.kind === 'tensor-product') {
337
+ throw new NumericalBackendError('lowering: nested tensor-product numerical evaluation is not supported in v0.3.5 — '
338
+ + 'flatten the contraction into a single product');
339
+ }
340
+ }
341
+ // Contractable operands (tensor-symbol / metric-tensor / kronecker-delta
342
+ // / tensor-partial-derivative) participate in the einsum; everything
343
+ // else must be a rank-0 scalar factor.
344
+ const operands = node.args.filter(isContractable);
345
+ const scalarArgs = node.args.filter((a) => !isContractable(a));
346
+ // computeContraction is the single authority on WHICH indices contract
347
+ // (variance-aware, implicit-metric rule). See buildEinsumSpec JSDoc.
348
+ // The recursive validateContractionChild resolves tensor-partial-derivative
349
+ // operands via validatePartialDerivative.
350
+ function validateContractionChild(child) {
351
+ if (child.kind === 'tensor-symbol')
352
+ return validateTensorSymbol(child);
353
+ if (child.kind === 'metric-tensor')
354
+ return validateMetricTensor(child);
355
+ if (child.kind === 'kronecker-delta')
356
+ return validateKroneckerDelta(child);
357
+ if (child.kind === 'tensor-partial-derivative') {
358
+ const r = validatePartialDerivative(child, (g) => validateContractionChild(g));
359
+ return { dim: r.dim, freeIndices: r.freeIndices };
360
+ }
361
+ throw new NumericalBackendError(`lowering: unexpected operand '${child.kind}' in tensor-product einsum`);
362
+ }
363
+ const { contractionPairs, freeIndices } = computeContraction(operands, validateContractionChild);
364
+ const spec = buildEinsumSpec(operands, contractionPairs, freeIndices);
365
+ const operandTensors = operands.map((n) => lowerContractable(n, inputs, engine));
366
+ let result = engine.einsum(spec, ...operandTensors);
367
+ // Scalar operands multiply the whole contraction.
368
+ for (const s of scalarArgs) {
369
+ const st = lowerNode(s, inputs, engine);
370
+ if (st.shape.length !== 0) {
371
+ throw new NumericalBackendError('lowering: non-scalar non-contractable operand in tensor-product');
372
+ }
373
+ result = engine.scale(result, engine.toNested(st));
374
+ }
375
+ return result;
376
+ }
377
+ case 'tensor-partial-derivative':
378
+ // v0.7 follow-up to v0.6.1 LOC miss: body extracted to
379
+ // derivative-lowering.ts. No recursive lowerNode call from
380
+ // this arm, so the thunk parameter is not needed.
381
+ return lowerTensorPartialDerivative(node, inputs, engine);
382
+ case 'covariant-derivative':
383
+ // v0.7 follow-up to v0.6.1 LOC miss: body extracted to
384
+ // derivative-lowering.ts. Recursive lowerNode call threaded
385
+ // via thunk to keep the module graph acyclic.
386
+ return lowerCovariantDerivative(node, inputs, engine, lowerNode);
387
+ case 'integral':
388
+ case 'derivative':
389
+ throw new NumericalBackendError(`lowering: '${node.kind}' is not numerically evaluated in v0.3.5 — `
390
+ + 'use tensor-partial-derivative for differentiation');
391
+ // v0.6.0 Task 3.10e: ricci-tensor, einstein-tensor, bianchi-residual,
392
+ // riemann-tensor, weyl-tensor, kretschmann-scalar all delegate to
393
+ // lowerCurvature — the extracted curvature-composite dispatcher.
394
+ case 'ricci-tensor':
395
+ case 'einstein-tensor':
396
+ case 'bianchi-residual':
397
+ case 'riemann-tensor':
398
+ case 'weyl-tensor':
399
+ case 'kretschmann-scalar':
400
+ return lowerCurvature(node, inputs, engine);
401
+ case 'killing-vector': {
402
+ // v0.6.0 Task 1.1: KillingVectorNode symbolic AST added. Numerical
403
+ // evaluation (verifyKillingEquation / evaluateConservedCharge) is
404
+ // deferred to Task 1.3 (src/numerical/killing.ts). Until then, the
405
+ // lowering layer raises a descriptive error so callers get a clear
406
+ // signal instead of the generic 'unknown kind' message.
407
+ throw new NumericalBackendError(`lowering: 'killing-vector' numerical evaluation is not yet implemented ` +
408
+ `(Task 1.3). Use verifyKillingEquation() from src/numerical/killing.ts.`);
409
+ }
410
+ case 'conserved-charge': {
411
+ // v0.6.0 Task 1.2: ConservedChargeNode symbolic AST added. Numerical
412
+ // evaluation (evaluateConservedCharge) is deferred to Task 1.3
413
+ // (src/numerical/killing.ts). Raises a descriptive error so callers
414
+ // get a clear signal instead of the generic 'unknown kind' message.
415
+ throw new NumericalBackendError(`lowering: 'conserved-charge' numerical evaluation is not yet implemented ` +
416
+ `(Task 1.3). Use evaluateConservedCharge() from src/numerical/killing.ts.`);
417
+ }
418
+ case 'stress-energy': {
419
+ // v0.6.0 Task 2.1: StressEnergyTensorNode symbolic AST added. Full
420
+ // numerical evaluation (T_μν from a perfect-fluid or explicit component
421
+ // map) is deferred to Task 2.4 (src/numerical/einstein-equation.ts).
422
+ // Raises a descriptive error so callers get a clear signal instead of
423
+ // the generic 'unknown kind' message from the exhaustiveness guard.
424
+ throw new NumericalBackendError(`lowering: 'stress-energy' numerical evaluation is not yet implemented ` +
425
+ `(Task 2.4). Use the Einstein-equation evaluator in src/numerical/einstein-equation.ts.`);
426
+ }
427
+ case 'cosmological-constant': {
428
+ // v0.6.0 Task 2.1: CosmologicalConstantNode symbolic AST added. Numerical
429
+ // evaluation (inject Λ as a scalar into the Einstein equation) is deferred
430
+ // to Task 2.4 (src/numerical/einstein-equation.ts).
431
+ throw new NumericalBackendError(`lowering: 'cosmological-constant' numerical evaluation is not yet implemented ` +
432
+ `(Task 2.4). Use the Einstein-equation evaluator in src/numerical/einstein-equation.ts.`);
433
+ }
434
+ case 'einstein-equation': {
435
+ // v0.6.0 Task 2.3: EinsteinFieldEquationNode predicate AST added. Numerical
436
+ // evaluation (G_μν + Λ g_μν = κ T_μν residual tensor) is deferred to
437
+ // Task 2.4 (src/numerical/einstein-equation.ts).
438
+ throw new NumericalBackendError(`lowering: 'einstein-equation' numerical evaluation is not yet implemented ` +
439
+ `(Task 2.4). Use the Einstein-equation evaluator in src/numerical/einstein-equation.ts.`);
440
+ }
630
441
  default: {
631
442
  const _exhaustive = node;
632
443
  void _exhaustive;