universal-physics-tensor 0.5.1 → 0.7.1

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 (378) 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 +15 -28
  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/index.d.ts +40 -1
  183. package/dist/bridges/index.d.ts.map +1 -1
  184. package/dist/bridges/index.js +130 -48
  185. package/dist/bridges/index.js.map +1 -1
  186. package/dist/bridges/perihelion-precession-labeled.d.ts +46 -0
  187. package/dist/bridges/perihelion-precession-labeled.d.ts.map +1 -0
  188. package/dist/bridges/perihelion-precession-labeled.js +54 -0
  189. package/dist/bridges/perihelion-precession-labeled.js.map +1 -0
  190. package/dist/core/axes-registry.d.ts +67 -0
  191. package/dist/core/axes-registry.d.ts.map +1 -0
  192. package/dist/core/axes-registry.js +75 -0
  193. package/dist/core/axes-registry.js.map +1 -0
  194. package/dist/core/cell.d.ts +176 -0
  195. package/dist/core/cell.d.ts.map +1 -0
  196. package/dist/core/cell.js +166 -0
  197. package/dist/core/cell.js.map +1 -0
  198. package/dist/core/flux-rules.d.ts +176 -0
  199. package/dist/core/flux-rules.d.ts.map +1 -0
  200. package/dist/core/flux-rules.js +329 -0
  201. package/dist/core/flux-rules.js.map +1 -0
  202. package/dist/core/labeled-tensor.d.ts +143 -0
  203. package/dist/core/labeled-tensor.d.ts.map +1 -0
  204. package/dist/core/labeled-tensor.js +275 -0
  205. package/dist/core/labeled-tensor.js.map +1 -0
  206. package/dist/core/regime-registry.d.ts +169 -0
  207. package/dist/core/regime-registry.d.ts.map +1 -0
  208. package/dist/core/regime-registry.js +174 -0
  209. package/dist/core/regime-registry.js.map +1 -0
  210. package/dist/core/regime-rule-install.d.ts +26 -0
  211. package/dist/core/regime-rule-install.d.ts.map +1 -0
  212. package/dist/core/regime-rule-install.js +90 -0
  213. package/dist/core/regime-rule-install.js.map +1 -0
  214. package/dist/core/regimes-builtins.d.ts +22 -0
  215. package/dist/core/regimes-builtins.d.ts.map +1 -0
  216. package/dist/core/regimes-builtins.js +96 -0
  217. package/dist/core/regimes-builtins.js.map +1 -0
  218. package/dist/core/tensor.d.ts +112 -0
  219. package/dist/core/tensor.d.ts.map +1 -1
  220. package/dist/core/tensor.js +366 -0
  221. package/dist/core/tensor.js.map +1 -1
  222. package/dist/core/types.d.ts +7 -2
  223. package/dist/core/types.d.ts.map +1 -1
  224. package/dist/core/types.js.map +1 -1
  225. package/dist/core/universal-index.d.ts +97 -0
  226. package/dist/core/universal-index.d.ts.map +1 -0
  227. package/dist/core/universal-index.js +70 -0
  228. package/dist/core/universal-index.js.map +1 -0
  229. package/dist/diff/bridge-gradient.d.ts +94 -0
  230. package/dist/diff/bridge-gradient.d.ts.map +1 -0
  231. package/dist/diff/bridge-gradient.js +83 -0
  232. package/dist/diff/bridge-gradient.js.map +1 -0
  233. package/dist/diff/bridge-specs.d.ts +68 -0
  234. package/dist/diff/bridge-specs.d.ts.map +1 -0
  235. package/dist/diff/bridge-specs.js +96 -0
  236. package/dist/diff/bridge-specs.js.map +1 -0
  237. package/dist/dimensional/bridge-check.d.ts.map +1 -1
  238. package/dist/dimensional/bridge-check.js +8 -0
  239. package/dist/dimensional/bridge-check.js.map +1 -1
  240. package/dist/dimensional/connection-validators.d.ts +12 -5
  241. package/dist/dimensional/connection-validators.d.ts.map +1 -1
  242. package/dist/dimensional/connection-validators.js.map +1 -1
  243. package/dist/dimensional/curvature-composite.d.ts +90 -0
  244. package/dist/dimensional/curvature-composite.d.ts.map +1 -0
  245. package/dist/dimensional/curvature-composite.js +57 -0
  246. package/dist/dimensional/curvature-composite.js.map +1 -0
  247. package/dist/dimensional/curvature-invariants.d.ts +90 -0
  248. package/dist/dimensional/curvature-invariants.d.ts.map +1 -0
  249. package/dist/dimensional/curvature-invariants.js +64 -0
  250. package/dist/dimensional/curvature-invariants.js.map +1 -0
  251. package/dist/dimensional/curvature.d.ts +46 -30
  252. package/dist/dimensional/curvature.d.ts.map +1 -1
  253. package/dist/dimensional/curvature.js.map +1 -1
  254. package/dist/dimensional/einstein-equation.d.ts +126 -0
  255. package/dist/dimensional/einstein-equation.d.ts.map +1 -0
  256. package/dist/dimensional/einstein-equation.js +122 -0
  257. package/dist/dimensional/einstein-equation.js.map +1 -0
  258. package/dist/dimensional/field-equation-helpers.d.ts +82 -0
  259. package/dist/dimensional/field-equation-helpers.d.ts.map +1 -0
  260. package/dist/dimensional/field-equation-helpers.js +123 -0
  261. package/dist/dimensional/field-equation-helpers.js.map +1 -0
  262. package/dist/dimensional/friedmann-equation.d.ts +148 -0
  263. package/dist/dimensional/friedmann-equation.d.ts.map +1 -0
  264. package/dist/dimensional/friedmann-equation.js +150 -0
  265. package/dist/dimensional/friedmann-equation.js.map +1 -0
  266. package/dist/dimensional/gauge-field.d.ts +182 -0
  267. package/dist/dimensional/gauge-field.d.ts.map +1 -0
  268. package/dist/dimensional/gauge-field.js +134 -0
  269. package/dist/dimensional/gauge-field.js.map +1 -0
  270. package/dist/dimensional/killing-validators.d.ts +94 -0
  271. package/dist/dimensional/killing-validators.d.ts.map +1 -0
  272. package/dist/dimensional/killing-validators.js +66 -0
  273. package/dist/dimensional/killing-validators.js.map +1 -0
  274. package/dist/dimensional/klein-gordon-equation.d.ts +113 -0
  275. package/dist/dimensional/klein-gordon-equation.d.ts.map +1 -0
  276. package/dist/dimensional/klein-gordon-equation.js +98 -0
  277. package/dist/dimensional/klein-gordon-equation.js.map +1 -0
  278. package/dist/dimensional/rg-flow.d.ts +156 -0
  279. package/dist/dimensional/rg-flow.d.ts.map +1 -0
  280. package/dist/dimensional/rg-flow.js +150 -0
  281. package/dist/dimensional/rg-flow.js.map +1 -0
  282. package/dist/dimensional/stress-energy-validators.d.ts +74 -0
  283. package/dist/dimensional/stress-energy-validators.d.ts.map +1 -0
  284. package/dist/dimensional/stress-energy-validators.js +47 -0
  285. package/dist/dimensional/stress-energy-validators.js.map +1 -0
  286. package/dist/dimensional/tensor-trace.d.ts +128 -0
  287. package/dist/dimensional/tensor-trace.d.ts.map +1 -0
  288. package/dist/dimensional/tensor-trace.js +95 -0
  289. package/dist/dimensional/tensor-trace.js.map +1 -0
  290. package/dist/dimensional/tensor.d.ts +6 -8
  291. package/dist/dimensional/tensor.d.ts.map +1 -1
  292. package/dist/dimensional/tensor.js +3 -1
  293. package/dist/dimensional/tensor.js.map +1 -1
  294. package/dist/dimensional/validator-registry.d.ts +90 -0
  295. package/dist/dimensional/validator-registry.d.ts.map +1 -0
  296. package/dist/dimensional/validator-registry.js +131 -0
  297. package/dist/dimensional/validator-registry.js.map +1 -0
  298. package/dist/dimensional/validator.d.ts +12 -2
  299. package/dist/dimensional/validator.d.ts.map +1 -1
  300. package/dist/dimensional/validator.js +60 -75
  301. package/dist/dimensional/validator.js.map +1 -1
  302. package/dist/dimensional/weyl-validators.d.ts +84 -0
  303. package/dist/dimensional/weyl-validators.d.ts.map +1 -0
  304. package/dist/dimensional/weyl-validators.js +84 -0
  305. package/dist/dimensional/weyl-validators.js.map +1 -0
  306. package/dist/index.d.ts +37 -0
  307. package/dist/index.d.ts.map +1 -1
  308. package/dist/index.js +41 -0
  309. package/dist/index.js.map +1 -1
  310. package/dist/numerical/be37-covariant-eikonal.d.ts +19 -0
  311. package/dist/numerical/be37-covariant-eikonal.d.ts.map +1 -1
  312. package/dist/numerical/be37-covariant-eikonal.js +29 -9
  313. package/dist/numerical/be37-covariant-eikonal.js.map +1 -1
  314. package/dist/numerical/christoffel-flat.d.ts +49 -0
  315. package/dist/numerical/christoffel-flat.d.ts.map +1 -0
  316. package/dist/numerical/christoffel-flat.js +86 -0
  317. package/dist/numerical/christoffel-flat.js.map +1 -0
  318. package/dist/numerical/curvature-lowering-helpers.d.ts +49 -57
  319. package/dist/numerical/curvature-lowering-helpers.d.ts.map +1 -1
  320. package/dist/numerical/curvature-lowering-helpers.js +109 -4
  321. package/dist/numerical/curvature-lowering-helpers.js.map +1 -1
  322. package/dist/numerical/derivative-lowering.d.ts +67 -0
  323. package/dist/numerical/derivative-lowering.d.ts.map +1 -0
  324. package/dist/numerical/derivative-lowering.js +243 -0
  325. package/dist/numerical/derivative-lowering.js.map +1 -0
  326. package/dist/numerical/einstein-equation.d.ts +106 -0
  327. package/dist/numerical/einstein-equation.d.ts.map +1 -0
  328. package/dist/numerical/einstein-equation.js +172 -0
  329. package/dist/numerical/einstein-equation.js.map +1 -0
  330. package/dist/numerical/geodesic-integrator.d.ts +7 -4
  331. package/dist/numerical/geodesic-integrator.d.ts.map +1 -1
  332. package/dist/numerical/geodesic-integrator.js +5 -1
  333. package/dist/numerical/geodesic-integrator.js.map +1 -1
  334. package/dist/numerical/gl4-integrator.d.ts +4 -2
  335. package/dist/numerical/gl4-integrator.d.ts.map +1 -1
  336. package/dist/numerical/gl4-integrator.js +24 -8
  337. package/dist/numerical/gl4-integrator.js.map +1 -1
  338. package/dist/numerical/killing.d.ts +157 -0
  339. package/dist/numerical/killing.d.ts.map +1 -0
  340. package/dist/numerical/killing.js +242 -0
  341. package/dist/numerical/killing.js.map +1 -0
  342. package/dist/numerical/kretschmann.d.ts +62 -0
  343. package/dist/numerical/kretschmann.d.ts.map +1 -0
  344. package/dist/numerical/kretschmann.js +88 -0
  345. package/dist/numerical/kretschmann.js.map +1 -0
  346. package/dist/numerical/lowering-utils.d.ts +47 -0
  347. package/dist/numerical/lowering-utils.d.ts.map +1 -0
  348. package/dist/numerical/lowering-utils.js +64 -0
  349. package/dist/numerical/lowering-utils.js.map +1 -0
  350. package/dist/numerical/lowering.d.ts +1 -29
  351. package/dist/numerical/lowering.d.ts.map +1 -1
  352. package/dist/numerical/lowering.js +219 -415
  353. package/dist/numerical/lowering.js.map +1 -1
  354. package/dist/numerical/null-ic.d.ts +40 -0
  355. package/dist/numerical/null-ic.d.ts.map +1 -0
  356. package/dist/numerical/null-ic.js +50 -0
  357. package/dist/numerical/null-ic.js.map +1 -0
  358. package/dist/numerical/null-ray-integrator.d.ts +3 -2
  359. package/dist/numerical/null-ray-integrator.d.ts.map +1 -1
  360. package/dist/numerical/painleve-gullstrand-metric.d.ts +74 -0
  361. package/dist/numerical/painleve-gullstrand-metric.d.ts.map +1 -0
  362. package/dist/numerical/painleve-gullstrand-metric.js +121 -0
  363. package/dist/numerical/painleve-gullstrand-metric.js.map +1 -0
  364. package/dist/numerical/pderiv.d.ts +17 -9
  365. package/dist/numerical/pderiv.d.ts.map +1 -1
  366. package/dist/numerical/pderiv.js +6 -3
  367. package/dist/numerical/pderiv.js.map +1 -1
  368. package/dist/numerical/perihelion-finder.d.ts +30 -0
  369. package/dist/numerical/perihelion-finder.d.ts.map +1 -1
  370. package/dist/numerical/perihelion-finder.js +30 -0
  371. package/dist/numerical/perihelion-finder.js.map +1 -1
  372. package/dist/numerical/tensor-engine.d.ts +2 -2
  373. package/dist/numerical/tensor-engine.d.ts.map +1 -1
  374. package/dist/numerical/weyl-lowering.d.ts +60 -0
  375. package/dist/numerical/weyl-lowering.d.ts.map +1 -0
  376. package/dist/numerical/weyl-lowering.js +111 -0
  377. package/dist/numerical/weyl-lowering.js.map +1 -0
  378. package/package.json +9 -7
@@ -10,24 +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, contractRiemannJS, } from './curvature-lowering-helpers.js';
20
- /**
21
- * v0.5.1 TS-2: module-private type predicate for the `metric-tensor`
22
- * AST kind. Replaces the duplicated `(n as { kind?: unknown }).kind ===
23
- * 'metric-tensor'` cast pattern that appeared at the covariant-derivative
24
- * lowering site; TypeScript narrows `covNode.gLower` to `MetricTensorNode`
25
- * after the predicate, removing the follow-up `as MetricTensorNode` cast.
26
- */
27
- function isMetricTensorNode(n) {
28
- return typeof n === 'object' && n !== null
29
- && n.kind === 'metric-tensor';
30
- }
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';
31
30
  function isContractable(node) {
32
31
  return node.kind === 'tensor-symbol'
33
32
  || node.kind === 'metric-tensor'
@@ -50,26 +49,6 @@ function operandIndices(node) {
50
49
  }
51
50
  return node.indices;
52
51
  }
53
- function dimensionOf(inputs) {
54
- return inputs.dimension ?? 4;
55
- }
56
- /** Look up a named tensor's concrete value, or throw. */
57
- function requireValue(name, inputs) {
58
- const v = inputs.tensors.get(name);
59
- if (v === undefined) {
60
- throw new NumericalBackendError(`lowering: no value supplied for "${name}" in inputs.tensors`);
61
- }
62
- return v;
63
- }
64
- /** Flatten a NestedArray to a plain number[] and check expected size.
65
- * Delegates to the canonical flattenNA() from connection-lowering-helpers. */
66
- function flattenNestedArray(data, expectedSize) {
67
- const out = flattenNA(data);
68
- if (out.length !== expectedSize) {
69
- throw new NumericalBackendError(`lowering: flattenNestedArray: got ${out.length} elements, expected ${expectedSize}`);
70
- }
71
- return out;
72
- }
73
52
  /**
74
53
  * Build the EinsumSpec for a flat tensor-product.
75
54
  *
@@ -80,9 +59,10 @@ function flattenNestedArray(data, expectedSize) {
80
59
  * labels to their (operand, axis) sites. There is exactly one
81
60
  * contraction-decision implementation in the codebase.
82
61
  *
83
- * @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.
84
64
  */
85
- export function buildEinsumSpec(operands, contractionPairs, freeIndices) {
65
+ function buildEinsumSpec(operands, contractionPairs, freeIndices) {
86
66
  // Map every label to its (operand, axis) sites — via operandIndices() so a
87
67
  // tensor-partial-derivative operand contributes its [...of.indices, wrtIndex]
88
68
  // effective axes.
@@ -131,349 +111,19 @@ function lowerContractable(node, inputs, engine) {
131
111
  const shape = node.indices.map(() => N);
132
112
  return engine.fromNested(requireValue(node.name, inputs), shape);
133
113
  }
134
- /** Lower a validated ExprNode to an EngineTensor.
135
- * @internal cross-module/test use only; not part of the consumer surface. */
136
- 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) {
137
126
  switch (node.kind) {
138
- case 'symbol':
139
- return engine.fromNested(requireValue(node.name, inputs), []);
140
- case 'tensor-symbol':
141
- case 'metric-tensor':
142
- case 'kronecker-delta':
143
- return lowerContractable(node, inputs, engine);
144
- case 'op': {
145
- if (node.op === '+' || node.op === '-') {
146
- if (node.args.length === 0)
147
- return engine.fromNested(0, []);
148
- let acc = lowerNode(node.args[0], inputs, engine);
149
- for (let i = 1; i < node.args.length; i++) {
150
- const next = lowerNode(node.args[i], inputs, engine);
151
- acc = node.op === '+' ? engine.add(acc, next) : engine.sub(acc, next);
152
- }
153
- return acc;
154
- }
155
- // '*' / '/' / '^' are scalar-only. Guard arity so an unvalidated AST
156
- // surfaces a clean NumericalBackendError instead of a raw TypeError
157
- // (zero-operand '/') or a silent NaN (wrong-arity '^'). The '*' case
158
- // with zero args is already fine — reduce(..., 1) returns 1.
159
- if (node.op === '/' && node.args.length === 0) {
160
- throw new NumericalBackendError("lowering: op '/' requires at least one operand");
161
- }
162
- if (node.op === '^' && node.args.length !== 2) {
163
- throw new NumericalBackendError(`lowering: op '^' requires exactly 2 operands (base, exponent), got ${node.args.length}`);
164
- }
165
- // '*' / '/' / '^' are scalar-only (the validator rejects tensor
166
- // operands). Lower each to rank-0, do the arithmetic in JS, lift back.
167
- const scalars = node.args.map((a) => {
168
- const t = lowerNode(a, inputs, engine);
169
- if (t.shape.length !== 0) {
170
- throw new NumericalBackendError(`lowering: op '${node.op}' got a rank-${t.shape.length} operand — scalar ops require rank-0`);
171
- }
172
- return engine.toNested(t);
173
- });
174
- let value;
175
- if (node.op === '*')
176
- value = scalars.reduce((a, b) => a * b, 1);
177
- else if (node.op === '/')
178
- value = scalars.reduce((a, b) => a / b);
179
- else
180
- value = Math.pow(scalars[0], scalars[1]); // '^'
181
- return engine.fromNested(value, []);
182
- }
183
- case 'tensor-product': {
184
- for (const arg of node.args) {
185
- if (arg.kind === 'tensor-product') {
186
- throw new NumericalBackendError('lowering: nested tensor-product numerical evaluation is not supported in v0.3.5 — '
187
- + 'flatten the contraction into a single product');
188
- }
189
- }
190
- // Contractable operands (tensor-symbol / metric-tensor / kronecker-delta
191
- // / tensor-partial-derivative) participate in the einsum; everything
192
- // else must be a rank-0 scalar factor.
193
- const operands = node.args.filter(isContractable);
194
- const scalarArgs = node.args.filter((a) => !isContractable(a));
195
- // computeContraction is the single authority on WHICH indices contract
196
- // (variance-aware, implicit-metric rule). See buildEinsumSpec JSDoc.
197
- // The recursive validateContractionChild resolves tensor-partial-derivative
198
- // operands via validatePartialDerivative.
199
- function validateContractionChild(child) {
200
- if (child.kind === 'tensor-symbol')
201
- return validateTensorSymbol(child);
202
- if (child.kind === 'metric-tensor')
203
- return validateMetricTensor(child);
204
- if (child.kind === 'kronecker-delta')
205
- return validateKroneckerDelta(child);
206
- if (child.kind === 'tensor-partial-derivative') {
207
- const r = validatePartialDerivative(child, (g) => validateContractionChild(g));
208
- return { dim: r.dim, freeIndices: r.freeIndices };
209
- }
210
- throw new NumericalBackendError(`lowering: unexpected operand '${child.kind}' in tensor-product einsum`);
211
- }
212
- const { contractionPairs, freeIndices } = computeContraction(operands, validateContractionChild);
213
- const spec = buildEinsumSpec(operands, contractionPairs, freeIndices);
214
- const operandTensors = operands.map((n) => lowerContractable(n, inputs, engine));
215
- let result = engine.einsum(spec, ...operandTensors);
216
- // Scalar operands multiply the whole contraction.
217
- for (const s of scalarArgs) {
218
- const st = lowerNode(s, inputs, engine);
219
- if (st.shape.length !== 0) {
220
- throw new NumericalBackendError('lowering: non-scalar non-contractable operand in tensor-product');
221
- }
222
- result = engine.scale(result, engine.toNested(st));
223
- }
224
- return result;
225
- }
226
- case 'tensor-partial-derivative': {
227
- // v0.3.5/v0.4.0 scope: `of` is a tensor-symbol or metric-tensor.
228
- // ∂_μ(of) adds the wrtIndex as a trailing axis — the result shape is
229
- // [...ofShape, N], NOT ofShape. (For BE-37, `of` = the scalar S is
230
- // rank-0, so ∂_μ S is the rank-1 wave covector k_μ, shape [N].)
231
- const of = node.of;
232
- // v0.4.0 extension: metric-tensor pderiv dispatch.
233
- if (of.kind === 'metric-tensor') {
234
- const mNode = of;
235
- const strategy = mNode.derivativeStrategy ?? 'computed';
236
- const N = dimensionOf(inputs);
237
- const coordLabel = node.wrtIndex.label;
238
- const ofShape = mNode.indices.map(() => N);
239
- const resultShape = [...ofShape, N];
240
- if (strategy === 'zero') {
241
- // ∂g = 0 everywhere (constant/flat metric).
242
- return zeroTensor(resultShape, engine);
243
- }
244
- if (strategy === 'supplied') {
245
- // Look up the N slices ∂_mu g for mu=0..N-1 and stack them as the
246
- // trailing axis. Key format: `${metricName}/${coordLabel}_${mu}`.
247
- // Result shape: [...ofShape, N] = [N, N, N] for a rank-2 metric.
248
- // Build as a flat array then convert to nested for engine.fromNested().
249
- const size = resultShape.reduce((a, b) => a * b, 1);
250
- const flat = new Array(size).fill(0);
251
- // ofShape = [N, N], resultShape = [N, N, N]
252
- // flat[i*N*N + j*N + mu] = (∂_mu g)[i][j]
253
- for (let mu = 0; mu < N; mu++) {
254
- const key = `${mNode.name}/${coordLabel}_${mu}`;
255
- const slice = inputs.metricDerivatives?.get(key);
256
- if (slice === undefined) {
257
- throw new NumericalBackendError(`lowering: metric-tensor pderiv with strategy='supplied': ` +
258
- `no metricDerivatives entry for "${key}"`);
259
- }
260
- // Flatten the slice (shape [N,N]) and write into flat at stride N (last axis)
261
- const flatSlice = flattenNestedArray(slice, N * N);
262
- for (let ij = 0; ij < N * N; ij++) {
263
- flat[ij * N + mu] = flatSlice[ij];
264
- }
265
- }
266
- return engine.fromNested(flatToNested(flat, resultShape), resultShape);
267
- }
268
- // strategy === 'computed': treat as zero for constant-tensor metrics
269
- // (the raw metric supplied via inputs.tensors has no coordinate dependence).
270
- return zeroTensor(resultShape, engine);
271
- }
272
- if (of.kind !== 'tensor-symbol') {
273
- throw new NumericalBackendError(`lowering: tensor-partial-derivative numerical eval requires a tensor-symbol `
274
- + `or metric-tensor 'of' operand in v0.3.5/v0.4.0 — got '${of.kind}'`);
275
- }
276
- const sym = of;
277
- const form = sym.numericalForm ?? 'symbolic';
278
- const coordLabel = node.wrtIndex.label;
279
- const N = dimensionOf(inputs);
280
- const ofShape = sym.indices.map(() => N);
281
- const resultShape = [...ofShape, N];
282
- if (form === 'symbolic') {
283
- // pderivSymbolic returns the caller-supplied full ∂_μ(of) tensor,
284
- // which must already be of shape [...ofShape, N].
285
- const d = pderivSymbolic(sym.name, coordLabel, inputs.derivatives ?? new Map());
286
- return engine.fromNested(d, resultShape);
287
- }
288
- if (form === 'numerical-fn') {
289
- // v0.3.5: 'numerical-fn' lowering is scoped to a rank-0 `of` (scalar
290
- // field). ∂_μ ranges over all N coordinate axes — stack the N
291
- // single-axis derivatives into the rank-1 result. Higher-rank fields
292
- // under 'numerical-fn' are a v0.4.0 concern.
293
- if (ofShape.length !== 0) {
294
- throw new NumericalBackendError(`lowering: 'numerical-fn' pderiv lowering supports a rank-0 'of' in v0.3.5; `
295
- + `"${sym.name}" is rank ${ofShape.length}`);
296
- }
297
- const fn = inputs.fields?.get(sym.name);
298
- if (!fn) {
299
- throw new NumericalBackendError(`lowering: 'numerical-fn' tensor-symbol "${sym.name}" has no field fn in inputs.fields`);
300
- }
301
- const coordValues = inputs.coords ? [...inputs.coords.values()] : [];
302
- const components = [];
303
- for (let axis = 0; axis < N; axis++) {
304
- components.push(pderivNumericalFn(fn, coordValues, axis));
305
- }
306
- return engine.fromNested(components, [N]);
307
- }
308
- // form === 'grid': the GridField is the field sampled over space, and
309
- // pderivGrid returns the derivative field sampled on that same grid —
310
- // result shape is grid.shape. This is a distinct semantic from
311
- // symbolic/numerical-fn (a sampled derivative field, not a single
312
- // tensor), kept as the v0.5.0 BSSN forward-compat path. v0.3.5 has no
313
- // release test driving 'grid' through lowering; pderivGrid itself is
314
- // unit-tested in Task 10's pderiv.test.ts.
315
- const grid = inputs.grids?.get(sym.name);
316
- if (!grid) {
317
- throw new NumericalBackendError(`lowering: 'grid' tensor-symbol "${sym.name}" has no GridField in inputs.grids`);
318
- }
319
- const gridAxis = inputs.coords ? [...inputs.coords.keys()].indexOf(coordLabel) : 0;
320
- const flat = pderivGrid(grid, gridAxis < 0 ? 0 : gridAxis);
321
- return engine.fromNested(flat.length === 1 ? flat[0] : flat, grid.shape);
322
- }
323
- case 'covariant-derivative': {
324
- // S2(a) fix: `of.freeIndices` does NOT exist on the raw ExprNode.
325
- // Re-validate the `of` subtree to obtain its free-index structure.
326
- const covNode = node;
327
- const ofExpr = covNode.of;
328
- // TS-2 runtime guard: `covNode.of` is typed as `unknown` (module-cycle
329
- // prevents ExprNode import in connection-validators.ts). The cast above
330
- // is unchecked — a malformed AST bypassing validate() would produce a
331
- // cryptic TypeError at `ofExpr.kind` below. Throw a clear message now.
332
- if (typeof ofExpr.kind !== 'string') {
333
- throw new NumericalBackendError(`lowering: CovariantDerivativeNode.of must have a string 'kind' field ` +
334
- `(got ${JSON.stringify(ofExpr.kind)}). ` +
335
- `Always call validate() before evaluateNumericalRaw().`);
336
- }
337
- const ofValidation = validate(ofExpr);
338
- // Build ordered list of free indices: [{label, variance}].
339
- // Iterate of.indices (NOT validation.freeIndices Map) — declaration order IS
340
- // the axis layout. For tensor-symbol and metric-tensor, of.indices is the
341
- // canonical axis order; the freeIndices Map insertion order is also
342
- // of.indices order (validateTensorSymbol iterates node.indices), but relying
343
- // on that is an undocumented invariant. Iterating of.indices directly makes
344
- // the axis ordering guarantee explicit and safe for future of-kinds.
345
- const ofFreeIndices = [];
346
- const ofIndices = ofExpr.indices;
347
- if (ofIndices) {
348
- // tensor-symbol / metric-tensor: iterate the declared indices in order.
349
- // Each index is either free (present in ofValidation.freeIndices) or
350
- // contracted (absent — skip). In practice, of.indices for a simple
351
- // tensor-symbol or metric-tensor has no contracted indices, but we
352
- // guard with the Map lookup for safety.
353
- for (const idx of ofIndices) {
354
- const counts = ofValidation.freeIndices.get(idx.label);
355
- if (counts === undefined)
356
- continue; // contracted — not a free axis
357
- ofFreeIndices.push({
358
- label: idx.label,
359
- variance: idx.variance,
360
- pos: ofFreeIndices.length,
361
- });
362
- }
363
- }
364
- else {
365
- // Fallback for future of-kinds without .indices (e.g. tensor-product).
366
- // Map iteration order is insertion order — a best-effort axis ordering.
367
- let axisPos = 0;
368
- for (const [label, counts] of ofValidation.freeIndices) {
369
- for (let i = 0; i < counts.upper; i++) {
370
- ofFreeIndices.push({ label, variance: 'upper', pos: axisPos++ });
371
- }
372
- for (let i = 0; i < counts.lower; i++) {
373
- ofFreeIndices.push({ label, variance: 'lower', pos: axisPos++ });
374
- }
375
- }
376
- }
377
- // Lower the operand tensor.
378
- const ofTensor = lowerNode(ofExpr, inputs, engine);
379
- const N = dimensionOf(inputs);
380
- // TS-2 runtime guard: gLower must be a metric-tensor node (validated
381
- // upstream). A malformed AST bypassing validate() could reach here with
382
- // a wrong kind, causing a silent wrong-path execution. The type
383
- // predicate narrows covNode.gLower to MetricTensorNode for the rest of
384
- // this branch — no follow-up cast needed.
385
- if (!isMetricTensorNode(covNode.gLower)) {
386
- throw new NumericalBackendError(`lowering: CovariantDerivativeNode.gLower must be a metric-tensor node ` +
387
- `(got kind='${covNode.gLower.kind}')`);
388
- }
389
- const strategy = covNode.gLower.derivativeStrategy ?? 'computed';
390
- // S2(b): strategy='zero' → flat space, Γ=0, ∇_μ T = ∂_μ T.
391
- // For constant tensors (like a flat metric), ∂_μ T = 0, so result is all zeros.
392
- // We return a zero tensor of shape [...ofShape, N] (wrt axis appended last).
393
- if (strategy === 'zero') {
394
- const outShape = [...ofTensor.shape, N];
395
- return zeroTensor(outShape, engine);
396
- }
397
- // v0.4.0 CRITICAL FIX (Finding #1): 'computed' on a raw-tensor metric means
398
- // constant metric → Γ = 0 → covariant-derivative = partial derivative only.
399
- // v0.5.0 will replace this with coordinate-grid finite-difference.
400
- // This early return MUST come before the Christoffel construction below,
401
- // because getMetricDerivFlat only accepts 'zero' | 'supplied'; if 'computed'
402
- // fell through, the type cast was silently wrong at runtime and the function
403
- // threw NumericalBackendError for every coordinate.
404
- //
405
- // Compute partial first so we can return it directly.
406
- // (partial is also needed by the 'supplied' path below, so we compute it
407
- // unconditionally and use the early return only for 'computed'.)
408
- //
409
- // UC-2 (v0.4.6): `of` is always tensor-symbol or metric-tensor at this
410
- // point. validateCovariantDerivative (connection-validators.ts) only
411
- // accepts those kinds for the 'of' field; any other kind fails dimensional
412
- // validation before evaluateNumerical reaches lowerNode. A covariant-
413
- // derivative with a scalar 'of' (ofFreeIndices.length === 0) already
414
- // returned at the early-return below. The old else-branch ("Scalar or
415
- // other: partial is zero") was therefore unreachable and is removed here;
416
- // replaced with an explicit throw to make the invariant visible if a
417
- // bypass-validate AST construction ever violates it.
418
- if (ofExpr.kind !== 'tensor-symbol' && ofExpr.kind !== 'metric-tensor') {
419
- throw new NumericalBackendError(`lowering: covariant-derivative 'of' must be tensor-symbol or metric-tensor ` +
420
- `(got '${ofExpr.kind}') — validated nodes cannot reach this point`);
421
- }
422
- const pdNode = {
423
- kind: 'tensor-partial-derivative',
424
- of: ofExpr,
425
- wrt: covNode.wrt,
426
- wrtIndex: covNode.wrtIndex,
427
- };
428
- const partial = lowerNode(pdNode, inputs, engine);
429
- // v0.4.0 spec: 'computed' on a raw-tensor metric = constant metric → Γ = 0.
430
- // The covariant-derivative reduces to the ordinary partial derivative.
431
- // v0.5.0 will add coordinate-grid finite-difference here.
432
- if (strategy === 'computed') {
433
- return partial;
434
- }
435
- // S2(c) + S2(d): Build Christoffel Γ^α_{μν} from metric data and apply
436
- // the sign rule to all free indices of `of`:
437
- // ∇_μ T^α_β = ∂_μ T^α_β + Γ^α_{μλ} T^λ_β − Γ^λ_{μβ} T^α_λ
438
- //
439
- // If `of` has no free indices (scalar), no correction needed.
440
- if (ofFreeIndices.length === 0) {
441
- return partial;
442
- }
443
- // Get metric and inverse metric data. gLower is already narrowed to
444
- // MetricTensorNode by the isMetricTensorNode guard above (TS-2);
445
- // gInverse retains its existing cast because no analogous predicate
446
- // exists for the inverse-metric kind yet.
447
- const gLowerNode = covNode.gLower;
448
- const gInverseNode = covNode.gInverse;
449
- const gInverseData = flattenNestedArray(requireValue(gInverseNode.name, inputs), N * N);
450
- // coordLabel for metricDerivatives keys (wrtIndex.label of the covariant derivative)
451
- const coordLabel = covNode.wrtIndex.label;
452
- // getMetricDeriv(mu): returns flat [N*N] of ∂_{mu} g
453
- const getMetricDeriv = (mu) => getMetricDerivFlat(gLowerNode.name, coordLabel, mu, 'supplied',
454
- // ^ strategy can only be 'supplied' here: 'zero' returned at line 457-459,
455
- // 'computed' returned at line 491-493, scalar 'of' returned at line 500-502.
456
- // Safe per audit UC-1: 'zero' strategy is short-circuited in earlier guard.
457
- N, inputs.metricDerivatives);
458
- // Compute Γ^α_{μν} from metric data.
459
- const GammaTensor = computeChristoffelTensor(gInverseData, getMetricDeriv, N, engine);
460
- const GammaFlat = flattenNestedArray(engine.toNested(GammaTensor), N * N * N);
461
- // Apply the Christoffel correction for each free index of `of`.
462
- // S2(d) sign rule: upper → +Γ, lower → −Γ.
463
- const ofFlat = flattenNestedArray(engine.toNested(ofTensor), ofTensor.shape.reduce((a, b) => a * b, 1));
464
- const ofShapeArr = [...ofTensor.shape];
465
- let correction = zeroTensorLike(partial, engine);
466
- for (const freeIdx of ofFreeIndices) {
467
- const term = contractChristoffelWithOperand(GammaFlat, ofFlat, ofShapeArr, freeIdx.pos, freeIdx.variance, N, engine);
468
- const sign = freeIdx.variance === 'upper' ? 1 : -1;
469
- correction = tensorAddScaled(correction, term, sign, engine);
470
- }
471
- return tensorAdd(partial, correction, engine);
472
- }
473
- case 'integral':
474
- case 'derivative':
475
- throw new NumericalBackendError(`lowering: '${node.kind}' is not numerically evaluated in v0.3.5 — `
476
- + 'use tensor-partial-derivative for differentiation');
477
127
  case 'ricci-tensor': {
478
128
  // v0.5.0 Task 7 — Ricci R_μν = R^λ_{μλν} (Carroll Eq. 3.91). Lowers
479
129
  // the embedded Riemann tensor via the 'riemann-tensor' case (so all
@@ -503,7 +153,8 @@ export function lowerNode(node, inputs, engine) {
503
153
  // composite node directly, no rewrite into a tensor-product.)
504
154
  const ricciNode = node;
505
155
  const N = dimensionOf(inputs);
506
- 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);
507
158
  const flatR = flattenNestedArray(engine.toNested(innerR), N * N * N * N);
508
159
  // Contract R[λ][μ_out][λ][ν_out] → Ricci[μ_out][ν_out] via the shared
509
160
  // `contractRiemannJS` helper (AS-1, v0.5.1). On R^ρ_{σμν} stored as
@@ -540,7 +191,7 @@ export function lowerNode(node, inputs, engine) {
540
191
  const ricciNodeInner = {
541
192
  kind: 'ricci-tensor', riemann: eNode.riemann,
542
193
  };
543
- const innerR = lowerNode(ricciNodeInner, inputs, engine);
194
+ const innerR = lowerCurvature(ricciNodeInner, inputs, engine);
544
195
  const Ric = engine.toNested(innerR);
545
196
  // Step 2: g_μν and g^μν from inputs.tensors (raw constant matrices at
546
197
  // the test coordinate point). Mirrors how ricci-tensor's de-Sitter
@@ -566,40 +217,9 @@ export function lowerNode(node, inputs, engine) {
566
217
  }
567
218
  case 'bianchi-residual': {
568
219
  // v0.5.0 Task 9 — Bianchi-identity residual B_{λμνρσ}.
569
- //
570
- // Approach 1 (full ∇, not raw ∂): cyclic sum
571
- // B_{λμνρσ} = ∇_λ R_{μνρσ} + ∇_μ R_{νλρσ} + ∇_ν R_{λμρσ}
572
- // where each ∇_λ R_{μνρσ} is computed with the four Christoffel-
573
- // correction terms (one per lower index of R). All FD/contraction
574
- // arithmetic happens in the helper module — this case just wires
575
- // x / metric closures from `inputs` to `bianchiResidualAt`.
576
- //
577
- // The result is a 5-deep nested array [N][N][N][N][N] with index order
578
- // B[λ][μ][ν][ρ][σ]. Returned as an EngineTensor of shape [N,N,N,N,N];
579
- // callers (typically bianchiResidual().evaluate) materialise via
580
- // engine.toNested.
581
- //
582
- // Walks the node directly — no AST rewrite into an op('+') of pderiv
583
- // products. Matches Task 6/7/8 walk-directly philosophy.
584
- const bNode = node;
585
- const rNode = bNode.riemann;
586
- const N = dimensionOf(inputs);
587
- // Coordinate value: same convention as the riemann-tensor case.
588
- const xCoordName = rNode.xCoord.name;
589
- const xRaw = requireValue(xCoordName, inputs);
590
- const x = flattenNestedArray(xRaw, N);
591
- // Coordinate-dependent metric closures.
592
- const gName = rNode.gLower.name;
593
- const gInvName = rNode.gInverse.name;
594
- const gFn = inputs.fields?.get(gName);
595
- const gInverseFn = inputs.fields?.get(gInvName);
596
- if (!gFn || !gInverseFn) {
597
- throw new NumericalBackendError(`lowering: bianchi-residual numerical evaluation requires coordinate-` +
598
- `dependent metric closures in inputs.fields for "${gName}" and "${gInvName}". ` +
599
- `Got fields=[${[...(inputs.fields?.keys() ?? [])].join(',')}].`);
600
- }
601
- const B = bianchiResidualAt(x, gFn, gInverseFn, N, engine);
602
- 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);
603
223
  }
604
224
  case 'riemann-tensor': {
605
225
  // v0.5.0 Task 6 (Phase 1c-ii). Walks the node directly (no AST rewrite
@@ -634,6 +254,190 @@ export function lowerNode(node, inputs, engine) {
634
254
  // Materialise back into an EngineTensor in [N,N,N,N] shape.
635
255
  return engine.fromNested(R, [N, N, N, N]);
636
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
+ }
637
441
  default: {
638
442
  const _exhaustive = node;
639
443
  void _exhaustive;