@classytic/stage 0.3.0 → 0.4.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 (431) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +18 -0
  2. package/dist/atomic/aufbau.d.mts +144 -0
  3. package/dist/atomic/aufbau.mjs +384 -0
  4. package/dist/atomic/elements.d.mts +67 -0
  5. package/dist/atomic/elements.mjs +785 -0
  6. package/dist/atomic/emission.d.mts +112 -0
  7. package/dist/atomic/emission.mjs +179 -0
  8. package/dist/atomic/index.d.mts +8 -0
  9. package/dist/atomic/index.mjs +9 -0
  10. package/dist/atomic/periodic.d.mts +82 -0
  11. package/dist/atomic/periodic.mjs +231 -0
  12. package/dist/atomic/properties.d.mts +100 -0
  13. package/dist/atomic/properties.mjs +574 -0
  14. package/dist/atomic/shells.d.mts +137 -0
  15. package/dist/atomic/shells.mjs +170 -0
  16. package/dist/atomic/trends.d.mts +148 -0
  17. package/dist/atomic/trends.mjs +225 -0
  18. package/dist/chem/chromatography.d.mts +66 -0
  19. package/dist/chem/chromatography.mjs +63 -0
  20. package/dist/chem/complex.d.mts +114 -0
  21. package/dist/chem/complex.mjs +234 -0
  22. package/dist/chem/cycle.d.mts +75 -0
  23. package/dist/chem/cycle.mjs +145 -0
  24. package/dist/chem/equation.d.mts +86 -0
  25. package/dist/chem/equation.mjs +168 -0
  26. package/dist/chem/formula.d.mts +90 -0
  27. package/dist/chem/formula.mjs +201 -0
  28. package/dist/chem/functional-groups.d.mts +31 -0
  29. package/dist/chem/functional-groups.mjs +187 -0
  30. package/dist/chem/hazard.d.mts +94 -0
  31. package/dist/chem/hazard.mjs +329 -0
  32. package/dist/chem/index.d.mts +34 -33
  33. package/dist/chem/index.mjs +34 -28
  34. package/dist/chem/ionic.d.mts +98 -0
  35. package/dist/chem/ionic.mjs +156 -0
  36. package/dist/chem/layout.d.mts +46 -0
  37. package/dist/chem/layout.mjs +342 -0
  38. package/dist/chem/lewis.d.mts +79 -0
  39. package/dist/chem/lewis.mjs +163 -0
  40. package/dist/chem/molecular-orbital.d.mts +114 -0
  41. package/dist/chem/molecular-orbital.mjs +201 -0
  42. package/dist/chem/molecule.d.mts +154 -0
  43. package/dist/chem/molecule.mjs +282 -0
  44. package/dist/chem/nmr.d.mts +153 -0
  45. package/dist/chem/nmr.mjs +165 -0
  46. package/dist/chem/polymer.d.mts +65 -0
  47. package/dist/chem/polymer.mjs +179 -0
  48. package/dist/chem/redox.d.mts +138 -0
  49. package/dist/chem/redox.mjs +328 -0
  50. package/dist/chem/relations.d.mts +183 -0
  51. package/dist/chem/relations.mjs +299 -0
  52. package/dist/chem/skeleton.d.mts +51 -0
  53. package/dist/chem/skeleton.mjs +186 -0
  54. package/dist/chem/solution.d.mts +116 -0
  55. package/dist/chem/solution.mjs +186 -0
  56. package/dist/chem/species.d.mts +47 -0
  57. package/dist/chem/species.mjs +128 -0
  58. package/dist/chem/stereo.d.mts +108 -0
  59. package/dist/chem/stereo.mjs +286 -0
  60. package/dist/chem/stoichiometry.d.mts +95 -0
  61. package/dist/chem/stoichiometry.mjs +145 -0
  62. package/dist/chem/synthesis.d.mts +113 -0
  63. package/dist/chem/synthesis.mjs +281 -0
  64. package/dist/chem/vsepr.d.mts +80 -0
  65. package/dist/chem/vsepr.mjs +247 -0
  66. package/dist/circuit/ac.d.mts +163 -0
  67. package/dist/circuit/ac.mjs +452 -0
  68. package/dist/circuit/dc.d.mts +92 -0
  69. package/dist/circuit/dc.mjs +333 -0
  70. package/dist/circuit/index.d.mts +5 -92
  71. package/dist/circuit/index.mjs +5 -332
  72. package/dist/circuit/network.d.mts +99 -0
  73. package/dist/circuit/network.mjs +440 -0
  74. package/dist/circuit/topology.d.mts +102 -0
  75. package/dist/circuit/topology.mjs +143 -0
  76. package/dist/colour/absorption.d.mts +79 -0
  77. package/dist/colour/absorption.mjs +137 -0
  78. package/dist/colour/index.d.mts +6 -0
  79. package/dist/colour/index.mjs +7 -0
  80. package/dist/colour/name.d.mts +14 -0
  81. package/dist/colour/name.mjs +76 -0
  82. package/dist/colour/observer.d.mts +31 -0
  83. package/dist/colour/observer.mjs +46 -0
  84. package/dist/colour/spectrum.d.mts +61 -0
  85. package/dist/colour/spectrum.mjs +108 -0
  86. package/dist/colour/srgb.d.mts +49 -0
  87. package/dist/colour/srgb.mjs +108 -0
  88. package/dist/core/constants.d.mts +138 -0
  89. package/dist/core/constants.mjs +139 -0
  90. package/dist/core/index.d.mts +3 -1
  91. package/dist/core/index.mjs +3 -1
  92. package/dist/core/vec3.d.mts +94 -0
  93. package/dist/core/vec3.mjs +123 -0
  94. package/dist/core/worked.d.mts +35 -0
  95. package/dist/core/worked.mjs +44 -0
  96. package/dist/electro/cell.d.mts +102 -0
  97. package/dist/electro/cell.mjs +170 -0
  98. package/dist/electro/conductivity.d.mts +157 -0
  99. package/dist/electro/conductivity.mjs +156 -0
  100. package/dist/electro/couples.d.mts +114 -0
  101. package/dist/electro/couples.mjs +334 -0
  102. package/dist/electro/electrolysis.d.mts +96 -0
  103. package/dist/electro/electrolysis.mjs +274 -0
  104. package/dist/electro/faraday.d.mts +150 -0
  105. package/dist/electro/faraday.mjs +118 -0
  106. package/dist/electro/index.d.mts +6 -0
  107. package/dist/electro/index.mjs +7 -0
  108. package/dist/finance/accounting/adjustments.d.mts +17 -0
  109. package/dist/finance/accounting/adjustments.mjs +202 -0
  110. package/dist/finance/accounting/analysis.d.mts +8 -0
  111. package/dist/finance/accounting/analysis.mjs +205 -0
  112. package/dist/finance/accounting/clubs.d.mts +21 -0
  113. package/dist/finance/accounting/clubs.mjs +217 -0
  114. package/dist/finance/accounting/company-statements.d.mts +7 -0
  115. package/dist/finance/accounting/company-statements.mjs +150 -0
  116. package/dist/finance/accounting/harness.d.mts +7 -0
  117. package/dist/finance/accounting/harness.mjs +45 -0
  118. package/dist/finance/accounting/index.d.mts +18 -0
  119. package/dist/finance/accounting/index.mjs +18 -0
  120. package/dist/finance/accounting/journalize.d.mts +16 -0
  121. package/dist/finance/accounting/journalize.mjs +128 -0
  122. package/dist/finance/accounting/manufacturing.d.mts +8 -0
  123. package/dist/finance/accounting/manufacturing.mjs +236 -0
  124. package/dist/finance/accounting/partnership.d.mts +7 -0
  125. package/dist/finance/accounting/partnership.mjs +152 -0
  126. package/dist/finance/accounting/period-case.d.mts +6 -0
  127. package/dist/finance/accounting/period-case.mjs +71 -0
  128. package/dist/finance/accounting/post.d.mts +9 -0
  129. package/dist/finance/accounting/post.mjs +84 -0
  130. package/dist/finance/accounting/precision.d.mts +9 -0
  131. package/dist/finance/accounting/precision.mjs +15 -0
  132. package/dist/finance/accounting/rules.d.mts +21 -0
  133. package/dist/finance/accounting/rules.mjs +37 -0
  134. package/dist/finance/accounting/solve.d.mts +28 -0
  135. package/dist/finance/accounting/solve.mjs +92 -0
  136. package/dist/finance/accounting/statements.d.mts +7 -0
  137. package/dist/finance/accounting/statements.mjs +142 -0
  138. package/dist/finance/accounting/types.d.mts +649 -0
  139. package/dist/finance/accounting/validate.d.mts +7 -0
  140. package/dist/finance/accounting/validate.mjs +67 -0
  141. package/dist/finance/accounting/verification.d.mts +24 -0
  142. package/dist/finance/accounting/verification.mjs +386 -0
  143. package/dist/finance/bizsim.d.mts +21 -39
  144. package/dist/finance/bizsim.mjs +276 -97
  145. package/dist/finance/index.d.mts +20 -43
  146. package/dist/finance/index.mjs +19 -77
  147. package/dist/finance/investment-math.d.mts +7 -0
  148. package/dist/finance/investment-math.mjs +18 -0
  149. package/dist/finance/management-accounting/budgeting.d.mts +7 -0
  150. package/dist/finance/management-accounting/budgeting.mjs +189 -0
  151. package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
  152. package/dist/finance/management-accounting/cash-budget.mjs +154 -0
  153. package/dist/finance/management-accounting/costing.d.mts +8 -0
  154. package/dist/finance/management-accounting/costing.mjs +175 -0
  155. package/dist/finance/management-accounting/decisions.d.mts +8 -0
  156. package/dist/finance/management-accounting/decisions.mjs +164 -0
  157. package/dist/finance/management-accounting/index.d.mts +13 -0
  158. package/dist/finance/management-accounting/index.mjs +13 -0
  159. package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
  160. package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
  161. package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
  162. package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
  163. package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
  164. package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
  165. package/dist/finance/management-accounting/management-case.d.mts +8 -0
  166. package/dist/finance/management-accounting/management-case.mjs +91 -0
  167. package/dist/finance/management-accounting/master-budget.d.mts +7 -0
  168. package/dist/finance/management-accounting/master-budget.mjs +137 -0
  169. package/dist/finance/management-accounting/production-costing.d.mts +8 -0
  170. package/dist/finance/management-accounting/production-costing.mjs +214 -0
  171. package/dist/finance/management-accounting/types.d.mts +644 -0
  172. package/dist/finance/management-accounting/variances.d.mts +7 -0
  173. package/dist/finance/management-accounting/variances.mjs +150 -0
  174. package/dist/index.d.mts +6 -6
  175. package/dist/index.mjs +1 -1
  176. package/dist/math/analysis.d.mts +61 -0
  177. package/dist/math/analysis.mjs +187 -0
  178. package/dist/math/answer-check.d.mts +50 -0
  179. package/dist/math/answer-check.mjs +106 -0
  180. package/dist/math/calculus.d.mts +4 -9
  181. package/dist/math/calculus.mjs +216 -7
  182. package/dist/math/complex.d.mts +93 -0
  183. package/dist/math/complex.mjs +239 -0
  184. package/dist/math/expr.d.mts +23 -0
  185. package/dist/math/expr.mjs +36 -0
  186. package/dist/math/index.d.mts +8 -22
  187. package/dist/math/index.mjs +8 -37
  188. package/dist/math/latex.mjs +2 -1
  189. package/dist/math/parse.mjs +1 -1
  190. package/dist/math/poly.d.mts +55 -0
  191. package/dist/math/poly.mjs +273 -0
  192. package/dist/math/rearrange.d.mts +14 -0
  193. package/dist/math/rearrange.mjs +125 -0
  194. package/dist/math/solve.d.mts +21 -0
  195. package/dist/math/solve.mjs +75 -0
  196. package/dist/networking/addressing.d.mts +26 -0
  197. package/dist/networking/addressing.mjs +33 -0
  198. package/dist/networking/cloud/access.d.mts +36 -0
  199. package/dist/networking/cloud/access.mjs +95 -0
  200. package/dist/networking/cloud/containers.d.mts +43 -0
  201. package/dist/networking/cloud/containers.mjs +54 -0
  202. package/dist/networking/cloud/edge.d.mts +17 -0
  203. package/dist/networking/cloud/edge.mjs +31 -0
  204. package/dist/networking/cloud/failure-domains.d.mts +19 -0
  205. package/dist/networking/cloud/failure-domains.mjs +22 -0
  206. package/dist/networking/cloud/geo-routing.d.mts +22 -0
  207. package/dist/networking/cloud/geo-routing.mjs +64 -0
  208. package/dist/networking/cloud/index.d.mts +18 -0
  209. package/dist/networking/cloud/index.mjs +19 -0
  210. package/dist/networking/cloud/inference-reliability.d.mts +30 -0
  211. package/dist/networking/cloud/inference-reliability.mjs +76 -0
  212. package/dist/networking/cloud/inference.d.mts +118 -0
  213. package/dist/networking/cloud/inference.mjs +179 -0
  214. package/dist/networking/cloud/infrastructure.d.mts +45 -0
  215. package/dist/networking/cloud/infrastructure.mjs +96 -0
  216. package/dist/networking/cloud/observability.d.mts +24 -0
  217. package/dist/networking/cloud/observability.mjs +34 -0
  218. package/dist/networking/cloud/orchestration.d.mts +32 -0
  219. package/dist/networking/cloud/orchestration.mjs +38 -0
  220. package/dist/networking/cloud/recovery.d.mts +21 -0
  221. package/dist/networking/cloud/recovery.mjs +27 -0
  222. package/dist/networking/cloud/releases.d.mts +42 -0
  223. package/dist/networking/cloud/releases.mjs +135 -0
  224. package/dist/networking/cloud/scaling.d.mts +25 -0
  225. package/dist/networking/cloud/scaling.mjs +65 -0
  226. package/dist/networking/cloud/secrets.d.mts +39 -0
  227. package/dist/networking/cloud/secrets.mjs +68 -0
  228. package/dist/networking/cloud/server-deployment.d.mts +29 -0
  229. package/dist/networking/cloud/server-deployment.mjs +72 -0
  230. package/dist/networking/cloud/storage.d.mts +16 -0
  231. package/dist/networking/cloud/storage.mjs +58 -0
  232. package/dist/networking/cloud/vpc.d.mts +18 -0
  233. package/dist/networking/cloud/vpc.mjs +100 -0
  234. package/dist/networking/delivery.d.mts +34 -0
  235. package/dist/networking/delivery.mjs +52 -0
  236. package/dist/networking/index.d.mts +47 -0
  237. package/dist/networking/index.mjs +47 -0
  238. package/dist/networking/ipv6.d.mts +28 -0
  239. package/dist/networking/ipv6.mjs +17 -0
  240. package/dist/networking/journeys.d.mts +83 -0
  241. package/dist/networking/journeys.mjs +161 -0
  242. package/dist/networking/models/airtime.d.mts +87 -0
  243. package/dist/networking/models/airtime.mjs +130 -0
  244. package/dist/networking/models/cellular.d.mts +157 -0
  245. package/dist/networking/models/cellular.mjs +252 -0
  246. package/dist/networking/models/encapsulation.d.mts +98 -0
  247. package/dist/networking/models/encapsulation.mjs +132 -0
  248. package/dist/networking/models/handover.d.mts +116 -0
  249. package/dist/networking/models/handover.mjs +209 -0
  250. package/dist/networking/models/handshake.d.mts +90 -0
  251. package/dist/networking/models/handshake.mjs +122 -0
  252. package/dist/networking/models/index.d.mts +14 -0
  253. package/dist/networking/models/index.mjs +15 -0
  254. package/dist/networking/models/media.d.mts +82 -0
  255. package/dist/networking/models/media.mjs +188 -0
  256. package/dist/networking/models/satellite.d.mts +86 -0
  257. package/dist/networking/models/satellite.mjs +121 -0
  258. package/dist/networking/models/spectrum.d.mts +83 -0
  259. package/dist/networking/models/spectrum.mjs +235 -0
  260. package/dist/networking/models/switch.d.mts +80 -0
  261. package/dist/networking/models/switch.mjs +155 -0
  262. package/dist/networking/models/vlan.d.mts +62 -0
  263. package/dist/networking/models/vlan.mjs +100 -0
  264. package/dist/networking/models/vpn.d.mts +66 -0
  265. package/dist/networking/models/vpn.mjs +125 -0
  266. package/dist/networking/models/wifi-privacy.d.mts +82 -0
  267. package/dist/networking/models/wifi-privacy.mjs +130 -0
  268. package/dist/networking/models/wifi.d.mts +240 -0
  269. package/dist/networking/models/wifi.mjs +562 -0
  270. package/dist/networking/nat-traversal.d.mts +24 -0
  271. package/dist/networking/nat-traversal.mjs +38 -0
  272. package/dist/networking/protocols.d.mts +17 -0
  273. package/dist/networking/protocols.mjs +57 -0
  274. package/dist/networking/queue.d.mts +12 -0
  275. package/dist/networking/queue.mjs +18 -0
  276. package/dist/networking/route-learning.d.mts +23 -0
  277. package/dist/networking/route-learning.mjs +43 -0
  278. package/dist/networking/routing.d.mts +11 -0
  279. package/dist/networking/routing.mjs +25 -0
  280. package/dist/networking/signals.d.mts +26 -0
  281. package/dist/networking/signals.mjs +35 -0
  282. package/dist/networking/subnet.d.mts +49 -0
  283. package/dist/networking/subnet.mjs +89 -0
  284. package/dist/networking/tcp-reliability.d.mts +24 -0
  285. package/dist/networking/tcp-reliability.mjs +38 -0
  286. package/dist/networking/topology/contract.d.mts +123 -0
  287. package/dist/networking/topology/index.d.mts +4 -0
  288. package/dist/networking/topology/index.mjs +4 -0
  289. package/dist/networking/topology/presets.d.mts +7 -0
  290. package/dist/networking/topology/presets.mjs +302 -0
  291. package/dist/networking/topology/simulation.d.mts +8 -0
  292. package/dist/networking/topology/simulation.mjs +179 -0
  293. package/dist/networking/wireless.d.mts +11 -0
  294. package/dist/networking/wireless.mjs +17 -0
  295. package/dist/optics/imaging.d.mts +218 -0
  296. package/dist/optics/imaging.mjs +276 -0
  297. package/dist/optics/index.d.mts +7 -0
  298. package/dist/optics/index.mjs +8 -0
  299. package/dist/optics/laws.d.mts +70 -0
  300. package/dist/optics/laws.mjs +195 -0
  301. package/dist/optics/prism.d.mts +148 -0
  302. package/dist/optics/prism.mjs +197 -0
  303. package/dist/optics/refraction.d.mts +201 -0
  304. package/dist/optics/refraction.mjs +270 -0
  305. package/dist/optics/wave-optics.d.mts +171 -0
  306. package/dist/optics/wave-optics.mjs +259 -0
  307. package/dist/physics/ac/index.d.mts +183 -0
  308. package/dist/physics/ac/index.mjs +203 -0
  309. package/dist/physics/dynamics/forces.d.mts +98 -0
  310. package/dist/physics/dynamics/forces.mjs +153 -0
  311. package/dist/physics/dynamics/friction.d.mts +76 -0
  312. package/dist/physics/dynamics/friction.mjs +119 -0
  313. package/dist/physics/dynamics/system.d.mts +68 -0
  314. package/dist/physics/dynamics/system.mjs +125 -0
  315. package/dist/physics/electrostatics/index.d.mts +169 -0
  316. package/dist/physics/electrostatics/index.mjs +249 -0
  317. package/dist/physics/energy/centre-of-mass.d.mts +115 -0
  318. package/dist/physics/energy/centre-of-mass.mjs +180 -0
  319. package/dist/physics/energy/conservation.d.mts +81 -0
  320. package/dist/physics/energy/conservation.mjs +129 -0
  321. package/dist/physics/energy/power.d.mts +90 -0
  322. package/dist/physics/energy/power.mjs +167 -0
  323. package/dist/physics/energy/spring.d.mts +73 -0
  324. package/dist/physics/energy/spring.mjs +129 -0
  325. package/dist/physics/energy/store.d.mts +63 -0
  326. package/dist/physics/energy/store.mjs +108 -0
  327. package/dist/physics/energy/theorem.d.mts +65 -0
  328. package/dist/physics/energy/theorem.mjs +113 -0
  329. package/dist/physics/energy/work.d.mts +114 -0
  330. package/dist/physics/energy/work.mjs +219 -0
  331. package/dist/physics/gravitation/body.d.mts +85 -0
  332. package/dist/physics/gravitation/body.mjs +168 -0
  333. package/dist/physics/gravitation/kepler.d.mts +127 -0
  334. package/dist/physics/gravitation/kepler.mjs +216 -0
  335. package/dist/physics/gravitation/law.d.mts +117 -0
  336. package/dist/physics/gravitation/law.mjs +175 -0
  337. package/dist/physics/gravitation/orbit.d.mts +119 -0
  338. package/dist/physics/gravitation/orbit.mjs +202 -0
  339. package/dist/physics/gravitation/potential.d.mts +114 -0
  340. package/dist/physics/gravitation/potential.mjs +202 -0
  341. package/dist/physics/gravitation/variation.d.mts +97 -0
  342. package/dist/physics/gravitation/variation.mjs +175 -0
  343. package/dist/physics/index.d.mts +35 -0
  344. package/dist/physics/index.mjs +36 -0
  345. package/dist/physics/integral-sweep.d.mts +63 -0
  346. package/dist/physics/integral-sweep.mjs +126 -0
  347. package/dist/physics/kinematics/equations.d.mts +47 -0
  348. package/dist/physics/kinematics/equations.mjs +126 -0
  349. package/dist/physics/kinematics/free-fall.d.mts +53 -0
  350. package/dist/physics/kinematics/free-fall.mjs +71 -0
  351. package/dist/physics/kinematics/given.d.mts +16 -0
  352. package/dist/physics/kinematics/given.mjs +55 -0
  353. package/dist/physics/kinematics/roots.d.mts +41 -0
  354. package/dist/physics/kinematics/roots.mjs +72 -0
  355. package/dist/physics/kinematics/solve.d.mts +52 -0
  356. package/dist/physics/kinematics/solve.mjs +172 -0
  357. package/dist/physics/magnetism/biot-savart.d.mts +161 -0
  358. package/dist/physics/magnetism/biot-savart.mjs +353 -0
  359. package/dist/physics/magnetism/flux.d.mts +94 -0
  360. package/dist/physics/magnetism/flux.mjs +313 -0
  361. package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
  362. package/dist/physics/magnetism/geomagnetism.mjs +184 -0
  363. package/dist/physics/magnetism/index.d.mts +12 -0
  364. package/dist/physics/magnetism/index.mjs +74 -0
  365. package/dist/physics/magnetism/lorentz.d.mts +28 -0
  366. package/dist/physics/magnetism/lorentz.mjs +88 -0
  367. package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
  368. package/dist/physics/magnetism/magnetic-force.mjs +169 -0
  369. package/dist/physics/momentum/collide.d.mts +77 -0
  370. package/dist/physics/momentum/collide.mjs +115 -0
  371. package/dist/physics/momentum/impulse.d.mts +89 -0
  372. package/dist/physics/momentum/impulse.mjs +159 -0
  373. package/dist/physics/momentum/planar.d.mts +60 -0
  374. package/dist/physics/momentum/planar.mjs +110 -0
  375. package/dist/physics/projectile.d.mts +107 -0
  376. package/dist/physics/projectile.mjs +185 -0
  377. package/dist/physics/rotation/angular.d.mts +85 -0
  378. package/dist/physics/rotation/angular.mjs +130 -0
  379. package/dist/physics/rotation/circular.d.mts +79 -0
  380. package/dist/physics/rotation/circular.mjs +131 -0
  381. package/dist/physics/rotation/inertia.d.mts +164 -0
  382. package/dist/physics/rotation/inertia.mjs +332 -0
  383. package/dist/physics/rotation/torque.d.mts +65 -0
  384. package/dist/physics/rotation/torque.mjs +134 -0
  385. package/dist/physics/vectors.d.mts +64 -0
  386. package/dist/physics/vectors.mjs +114 -0
  387. package/dist/quantity/index.d.mts +119 -0
  388. package/dist/quantity/index.mjs +417 -0
  389. package/dist/relation/derive.d.mts +74 -0
  390. package/dist/relation/derive.mjs +73 -0
  391. package/dist/relation/index.d.mts +56 -0
  392. package/dist/relation/index.mjs +234 -0
  393. package/dist/scene/evaluators.mjs +1 -1
  394. package/dist/sim/thermal.mjs +45 -20
  395. package/dist/thermo/calorimetry.d.mts +207 -0
  396. package/dist/thermo/calorimetry.mjs +345 -0
  397. package/dist/thermo/cycles.d.mts +142 -0
  398. package/dist/thermo/cycles.mjs +256 -0
  399. package/dist/thermo/entropy.d.mts +87 -0
  400. package/dist/thermo/entropy.mjs +140 -0
  401. package/dist/thermo/expansion.d.mts +130 -0
  402. package/dist/thermo/expansion.mjs +178 -0
  403. package/dist/thermo/gas.d.mts +197 -0
  404. package/dist/thermo/gas.mjs +279 -0
  405. package/dist/thermo/heat-transfer.d.mts +164 -0
  406. package/dist/thermo/heat-transfer.mjs +217 -0
  407. package/dist/thermo/index.d.mts +9 -82
  408. package/dist/thermo/index.mjs +9 -132
  409. package/dist/thermo/processes.d.mts +95 -0
  410. package/dist/thermo/processes.mjs +154 -0
  411. package/dist/thermo/temperature.d.mts +174 -0
  412. package/dist/thermo/temperature.mjs +236 -0
  413. package/dist/waves/damping.d.mts +224 -0
  414. package/dist/waves/damping.mjs +317 -0
  415. package/dist/waves/doppler.d.mts +72 -0
  416. package/dist/waves/doppler.mjs +125 -0
  417. package/dist/waves/index.d.mts +10 -0
  418. package/dist/waves/index.mjs +10 -0
  419. package/dist/waves/pendulum.d.mts +130 -0
  420. package/dist/waves/pendulum.mjs +211 -0
  421. package/dist/waves/pitch.d.mts +125 -0
  422. package/dist/waves/pitch.mjs +158 -0
  423. package/dist/waves/shm.d.mts +170 -0
  424. package/dist/waves/shm.mjs +279 -0
  425. package/dist/waves/springs.d.mts +103 -0
  426. package/dist/waves/springs.mjs +176 -0
  427. package/dist/waves/superposition.d.mts +124 -0
  428. package/dist/waves/superposition.mjs +196 -0
  429. package/dist/waves/wave.d.mts +154 -0
  430. package/dist/waves/wave.mjs +178 -0
  431. package/package.json +74 -2
@@ -0,0 +1,417 @@
1
+ //#region src/quantity/index.ts
2
+ /**
3
+ * quantity, a number that knows its unit.
4
+ *
5
+ * The model: every quantity is stored as its value in SI BASE UNITS plus a dimension vector over
6
+ * (kg, m, s, mol, K, A). A unit string is a recipe for converting to that pair, so arithmetic is
7
+ * ordinary arithmetic on the SI values and integer addition on the exponents:
8
+ *
9
+ * a · b → si = a.si · b.si, dim = a.dim + b.dim
10
+ * a / b → si = a.si / b.si, dim = a.dim − b.dim
11
+ * a ± b → requires a.dim = b.dim
12
+ *
13
+ * Why this matters more than it looks. "Choose the right formula" is, operationally, "choose the
14
+ * one whose units cancel to the unit the answer is in", and cm³-against-dm³ is the single most
15
+ * common arithmetic error in A-level chemistry. Under this model that error cannot be made:
16
+ *
17
+ * qty(0.100, 'mol/dm3').times(qty(24.50, 'cm3')) → 2.45e-3 mol
18
+ *
19
+ * is simply correct, because both volumes reduce to m³ and the factors cancel. (An earlier plan
20
+ * said this case should THROW, on the grounds that cm³ "is not" dm³. That would be a worse design:
21
+ * it rejects a valid calculation and leaves the author to do the conversion by hand, which is the
22
+ * step that goes wrong.) What does throw is genuine nonsense: adding a mass to a volume, or asking
23
+ * for a mass in dm³.
24
+ *
25
+ * SCOPE, deliberately small: dimensional analysis over a fixed table of the units the Cambridge
26
+ * syllabuses actually use. Not a general units library, not arbitrary dimensional algebra, no
27
+ * user-defined units. The whole of A-level chemistry and physics fits in the table below.
28
+ *
29
+ * Pure: no React, no pixels.
30
+ */
31
+ /** SI base dimensions. Everything in the table reduces to integer powers of these. */
32
+ const BASE = [
33
+ "kg",
34
+ "m",
35
+ "s",
36
+ "mol",
37
+ "K",
38
+ "A"
39
+ ];
40
+ const DIMENSIONLESS = {};
41
+ const u = (dim, factor = 1, offset) => offset === void 0 ? {
42
+ dim,
43
+ factor
44
+ } : {
45
+ dim,
46
+ factor,
47
+ offset
48
+ };
49
+ /**
50
+ * The atomic units. Volume units are atomic (`dm3`, not `dm` cubed) because that is how they are
51
+ * written and it keeps the parser from having to read `dm3` as d·m·3.
52
+ */
53
+ const UNITS = {
54
+ "1": u(DIMENSIONLESS),
55
+ "%": u(DIMENSIONLESS, .01),
56
+ mol: u({ mol: 1 }),
57
+ mmol: u({ mol: 1 }, .001),
58
+ kg: u({ kg: 1 }),
59
+ g: u({ kg: 1 }, .001),
60
+ mg: u({ kg: 1 }, 1e-6),
61
+ tonne: u({ kg: 1 }, 1e3),
62
+ m: u({ m: 1 }),
63
+ cm: u({ m: 1 }, .01),
64
+ mm: u({ m: 1 }, .001),
65
+ km: u({ m: 1 }, 1e3),
66
+ m3: u({ m: 3 }),
67
+ dm3: u({ m: 3 }, .001),
68
+ cm3: u({ m: 3 }, 1e-6),
69
+ L: u({ m: 3 }, .001),
70
+ mL: u({ m: 3 }, 1e-6),
71
+ s: u({ s: 1 }),
72
+ ms: u({ s: 1 }, .001),
73
+ min: u({ s: 1 }, 60),
74
+ h: u({ s: 1 }, 3600),
75
+ K: u({ K: 1 }),
76
+ degC: u({ K: 1 }, 1, 273.15),
77
+ J: u({
78
+ kg: 1,
79
+ m: 2,
80
+ s: -2
81
+ }),
82
+ kJ: u({
83
+ kg: 1,
84
+ m: 2,
85
+ s: -2
86
+ }, 1e3),
87
+ MJ: u({
88
+ kg: 1,
89
+ m: 2,
90
+ s: -2
91
+ }, 1e6),
92
+ /**
93
+ * The kilowatt-hour: an energy, despite being spelled out of two units that both sound like rates.
94
+ * It is on every electricity bill and it is the standard way to catch out a student who has not
95
+ * separated power from energy, so it is worth being able to declare and convert rather than
96
+ * leaving it as a piece of folklore. 1 kWh = 1000 W x 3600 s = 3.6 MJ.
97
+ */
98
+ kWh: u({
99
+ kg: 1,
100
+ m: 2,
101
+ s: -2
102
+ }, 36e5),
103
+ N: u({
104
+ kg: 1,
105
+ m: 1,
106
+ s: -2
107
+ }),
108
+ kN: u({
109
+ kg: 1,
110
+ m: 1,
111
+ s: -2
112
+ }, 1e3),
113
+ W: u({
114
+ kg: 1,
115
+ m: 2,
116
+ s: -3
117
+ }),
118
+ kW: u({
119
+ kg: 1,
120
+ m: 2,
121
+ s: -3
122
+ }, 1e3),
123
+ MW: u({
124
+ kg: 1,
125
+ m: 2,
126
+ s: -3
127
+ }, 1e6),
128
+ /**
129
+ * Horsepower, which is a power like any other despite not being SI. Declared because questions in
130
+ * this market quote pump and motor ratings in it, and because there are TWO of them: this is the
131
+ * mechanical one that exam boards mean, 745.7 W. The metric horsepower (735.5 W) is what a car
132
+ * brochure means, and mixing them is a one per cent error that looks like a rounding difference.
133
+ */
134
+ hp: u({
135
+ kg: 1,
136
+ m: 2,
137
+ s: -3
138
+ }, 745.699872),
139
+ Hz: u({ s: -1 }),
140
+ /**
141
+ * Angles are dimensionless, which is why `sin(theta)` passes the argument check whichever of
142
+ * these is declared. They are still worth having as units, because the conversion is the step
143
+ * that goes wrong: a launch angle arrives from a question in degrees and every trig function in
144
+ * the language wants radians. Declaring a relation's angle as `rad` and passing `qty(30, 'deg')`
145
+ * converts once, at the boundary, instead of at each call site.
146
+ */
147
+ rad: u(DIMENSIONLESS),
148
+ deg: u(DIMENSIONLESS, Math.PI / 180),
149
+ rev: u(DIMENSIONLESS, 2 * Math.PI),
150
+ Pa: u({
151
+ kg: 1,
152
+ m: -1,
153
+ s: -2
154
+ }),
155
+ kPa: u({
156
+ kg: 1,
157
+ m: -1,
158
+ s: -2
159
+ }, 1e3),
160
+ atm: u({
161
+ kg: 1,
162
+ m: -1,
163
+ s: -2
164
+ }, 101325),
165
+ bar: u({
166
+ kg: 1,
167
+ m: -1,
168
+ s: -2
169
+ }, 1e5),
170
+ A: u({ A: 1 }),
171
+ C: u({
172
+ s: 1,
173
+ A: 1
174
+ }),
175
+ V: u({
176
+ kg: 1,
177
+ m: 2,
178
+ s: -3,
179
+ A: -1
180
+ })
181
+ };
182
+ /** Named SI-coherent units, for naming the result of an arithmetic operation. */
183
+ const NAMED = [
184
+ ["mol", { mol: 1 }],
185
+ ["kg", { kg: 1 }],
186
+ ["m", { m: 1 }],
187
+ ["s", { s: 1 }],
188
+ ["K", { K: 1 }],
189
+ ["A", { A: 1 }],
190
+ ["m3", { m: 3 }],
191
+ ["J", {
192
+ kg: 1,
193
+ m: 2,
194
+ s: -2
195
+ }],
196
+ ["N", {
197
+ kg: 1,
198
+ m: 1,
199
+ s: -2
200
+ }],
201
+ ["W", {
202
+ kg: 1,
203
+ m: 2,
204
+ s: -3
205
+ }],
206
+ ["Hz", { s: -1 }],
207
+ ["Pa", {
208
+ kg: 1,
209
+ m: -1,
210
+ s: -2
211
+ }],
212
+ ["C", {
213
+ s: 1,
214
+ A: 1
215
+ }],
216
+ ["V", {
217
+ kg: 1,
218
+ m: 2,
219
+ s: -3,
220
+ A: -1
221
+ }]
222
+ ];
223
+ function combineDim(a, b, sign) {
224
+ const out = {};
225
+ for (const k of BASE) {
226
+ const n = (a[k] ?? 0) + sign * (b[k] ?? 0);
227
+ if (n !== 0) out[k] = n;
228
+ }
229
+ return out;
230
+ }
231
+ const mulDim = (a, b) => combineDim(a, b, 1);
232
+ const divDim = (a, b) => combineDim(a, b, -1);
233
+ /** Raise a dimension to an integer power. A fractional power is legal only if it leaves every
234
+ * exponent an integer, which is what makes `sqrt(Ka·c)` work and `sqrt(mol)` fail. */
235
+ function powDim(a, n) {
236
+ const out = {};
237
+ for (const k of BASE) {
238
+ const e = (a[k] ?? 0) * n;
239
+ if (e === 0) continue;
240
+ if (!Number.isInteger(e)) throw new Error(`${formatDimension(a)}^${n} has a fractional dimension, which is not a unit`);
241
+ out[k] = e;
242
+ }
243
+ return out;
244
+ }
245
+ const sameDim = (a, b) => BASE.every((k) => (a[k] ?? 0) === (b[k] ?? 0));
246
+ const isDimensionless = (a) => BASE.every((k) => (a[k] ?? 0) === 0);
247
+ /** For error messages, where "1" would read as a number rather than as "has no units". */
248
+ const describeDimension = (d) => isDimensionless(d) ? "dimensionless" : formatDimension(d);
249
+ /**
250
+ * "kg·m^2/s^2·mol": readable in an error message AND parseable by `parseUnit`.
251
+ *
252
+ * Both properties are required. It names the dimension in messages, and it also names the unit of
253
+ * a quantity produced by arithmetic, which is then re-read the next time that quantity is used. An
254
+ * earlier version emitted `m2`, which reads back as an unknown unit rather than as m², so a
255
+ * perfectly good result became unusable one operation later.
256
+ */
257
+ function formatDimension(d) {
258
+ const show = (k, e) => e === 1 ? k : `${k}^${e}`;
259
+ const top = BASE.filter((k) => (d[k] ?? 0) > 0).map((k) => show(k, d[k]));
260
+ const bot = BASE.filter((k) => (d[k] ?? 0) < 0).map((k) => show(k, -d[k]));
261
+ if (!top.length && !bot.length) return "1";
262
+ return `${top.join("·") || "1"}${bot.length ? `/${bot.join("·")}` : ""}`;
263
+ }
264
+ const cache = /* @__PURE__ */ new Map();
265
+ /**
266
+ * Resolve a unit string to a dimension and a factor.
267
+ *
268
+ * Grammar: atoms separated by `·`, `*` or a space are multiplied; **every** segment after a `/` is
269
+ * a denominator, so `J/K/mol` is J·K⁻¹·mol⁻¹. That reading is the chemistry convention and it is
270
+ * stated here because `a/b/c` is genuinely ambiguous in general.
271
+ *
272
+ * An atom may carry an integer exponent written with a caret: `mol^2`, `dm3^2` (which is dm⁶, the
273
+ * denominator of a Ksp for a 1:2 salt). The caret is REQUIRED rather than optional, because a
274
+ * trailing digit is already part of the name in `dm3` and `cm3`, so `dm6` would have to be read as
275
+ * both a name and a power.
276
+ */
277
+ function parseUnit(spec) {
278
+ const hit = cache.get(spec);
279
+ if (hit) return hit;
280
+ const segments = spec.trim().split("/");
281
+ if (segments.length === 0 || segments[0].trim() === "") throw new Error(`Unit "${spec}" is empty`);
282
+ let dim = DIMENSIONLESS;
283
+ let factor = 1;
284
+ let offset;
285
+ let atomCount = 0;
286
+ segments.forEach((segment, index) => {
287
+ const atoms = segment.split(/[·*\s]+/).map((a) => a.trim()).filter(Boolean);
288
+ if (!atoms.length) throw new Error(`Unit "${spec}" has an empty part`);
289
+ for (const atom of atoms) {
290
+ const caret = atom.indexOf("^");
291
+ const name = caret === -1 ? atom : atom.slice(0, caret);
292
+ const power = caret === -1 ? 1 : Number(atom.slice(caret + 1));
293
+ if (!Number.isInteger(power) || power === 0) throw new Error(`Exponent in "${atom}" must be a non-zero integer`);
294
+ const def = UNITS[name];
295
+ if (!def) throw new Error(`Unknown unit "${name}" in "${spec}". Add it to the table if the syllabus uses it.`);
296
+ atomCount++;
297
+ if (def.offset !== void 0) offset = def.offset;
298
+ const signed = index === 0 ? power : -power;
299
+ dim = mulDim(dim, powDim(def.dim, signed));
300
+ factor *= Math.pow(def.factor, signed);
301
+ }
302
+ });
303
+ if (offset !== void 0 && atomCount > 1) throw new Error(`"${spec}" combines degC with another unit. A temperature on the Celsius scale is a point, not a size; use K.`);
304
+ const resolved = offset === void 0 ? {
305
+ dim,
306
+ factor
307
+ } : {
308
+ dim,
309
+ factor,
310
+ offset
311
+ };
312
+ cache.set(spec, resolved);
313
+ return resolved;
314
+ }
315
+ /** The units this kernel knows, for an error message or an editor. */
316
+ const knownUnits = () => Object.keys(UNITS);
317
+ /**
318
+ * A value with a unit. Immutable: every operation returns a new Quantity.
319
+ *
320
+ * `si` is the value in SI base units and is the single source of truth; `unit` is only how it is
321
+ * currently being displayed.
322
+ */
323
+ var Quantity = class Quantity {
324
+ si;
325
+ dim;
326
+ unit;
327
+ /** True only for a Celsius temperature. Carried rather than re-derived: see `requireScale`. */
328
+ onScale;
329
+ constructor(si, dim, unit, onScale = false) {
330
+ this.si = si;
331
+ this.dim = dim;
332
+ this.unit = unit;
333
+ this.onScale = onScale;
334
+ }
335
+ static of(value, unit) {
336
+ const r = parseUnit(unit);
337
+ return new Quantity(value * r.factor + (r.offset ?? 0), r.dim, unit, r.offset !== void 0);
338
+ }
339
+ /** Build directly from an SI value, naming the unit from the dimension. */
340
+ static fromSI(si, dim) {
341
+ return new Quantity(si, dim, canonicalUnit(dim));
342
+ }
343
+ /** The number, expressed in `this.unit`. */
344
+ get value() {
345
+ return this.in(this.unit);
346
+ }
347
+ /** The number, expressed in `unit`. Throws if the dimensions differ. */
348
+ in(unit) {
349
+ const r = parseUnit(unit);
350
+ if (!sameDim(this.dim, r.dim)) throw new Error(`Cannot express ${describeDimension(this.dim)} in "${unit}" (${describeDimension(r.dim)}).`);
351
+ return (this.si - (r.offset ?? 0)) / r.factor;
352
+ }
353
+ /** The same quantity, displayed in `unit`. */
354
+ to(unit) {
355
+ const r = parseUnit(unit);
356
+ if (!sameDim(this.dim, r.dim)) throw new Error(`Cannot convert ${describeDimension(this.dim)} to "${unit}" (${describeDimension(r.dim)}).`);
357
+ return new Quantity(this.si, this.dim, unit, r.offset !== void 0);
358
+ }
359
+ requireScale(op) {
360
+ if (this.onScale) throw new Error(`Cannot ${op} a temperature on the Celsius scale. Convert to K first: .to('K').`);
361
+ }
362
+ times(other) {
363
+ this.requireScale("multiply");
364
+ if (typeof other === "number") return new Quantity(this.si * other, this.dim, this.unit);
365
+ other.requireScale("multiply");
366
+ return Quantity.fromSI(this.si * other.si, mulDim(this.dim, other.dim));
367
+ }
368
+ over(other) {
369
+ this.requireScale("divide");
370
+ if (typeof other === "number") return new Quantity(this.si / other, this.dim, this.unit);
371
+ other.requireScale("divide");
372
+ return Quantity.fromSI(this.si / other.si, divDim(this.dim, other.dim));
373
+ }
374
+ plus(other) {
375
+ this.requireSame(other, "add");
376
+ return new Quantity(this.si + other.si, this.dim, this.unit);
377
+ }
378
+ /**
379
+ * Note what this CANNOT do: subtract two Celsius temperatures. The SI difference would be right
380
+ * (a kelvin interval) but the result would be displayed back on the Celsius scale, where 12.5 K
381
+ * reads as −260.65 °C. `requireScale` refuses it, and `.to('K')` on both sides is the fix.
382
+ */
383
+ minus(other) {
384
+ this.requireSame(other, "subtract");
385
+ return new Quantity(this.si - other.si, this.dim, this.unit);
386
+ }
387
+ pow(n) {
388
+ this.requireScale("raise to a power");
389
+ return Quantity.fromSI(Math.pow(this.si, n), powDim(this.dim, n));
390
+ }
391
+ requireSame(other, op) {
392
+ this.requireScale(op);
393
+ other.requireScale(op);
394
+ if (!sameDim(this.dim, other.dim)) throw new Error(`Cannot ${op} ${describeDimension(this.dim)} and ${describeDimension(other.dim)}.`);
395
+ }
396
+ /** Equal within a RELATIVE tolerance (default 1e-9), after reducing both to SI. */
397
+ equals(other, tol = 1e-9) {
398
+ if (!sameDim(this.dim, other.dim)) return false;
399
+ return Math.abs(this.si - other.si) <= tol * Math.max(1, Math.abs(this.si), Math.abs(other.si));
400
+ }
401
+ /** "2.45e-3 mol", at `sf` significant figures. */
402
+ toString(sf = 3) {
403
+ const v = this.value;
404
+ return `${Number.isFinite(v) ? Number(v.toPrecision(sf)) : v} ${this.unit === "1" ? "" : this.unit}`.trim();
405
+ }
406
+ };
407
+ /** `qty(24.50, 'cm3')`. */
408
+ const qty = (value, unit) => Quantity.of(value, unit);
409
+ /** The SI-coherent name for a dimension: 'mol', 'J', or a composed 'kg·m2/s2'. */
410
+ function canonicalUnit(dim) {
411
+ if (isDimensionless(dim)) return "1";
412
+ for (const [name, d] of NAMED) if (sameDim(dim, d)) return name;
413
+ return formatDimension(dim);
414
+ }
415
+
416
+ //#endregion
417
+ export { DIMENSIONLESS, Quantity, canonicalUnit, describeDimension, divDim, formatDimension, isDimensionless, knownUnits, mulDim, parseUnit, powDim, qty, sameDim };
@@ -0,0 +1,74 @@
1
+ import { Relation } from "./index.mjs";
2
+
3
+ //#region src/relation/derive.d.ts
4
+ /** One application of a known relation on the way to the target. */
5
+ interface DerivationStep {
6
+ /** The relation being used. A getter, so a lazily built one stays lazy. */
7
+ readonly relation: () => Relation;
8
+ /**
9
+ * Which variable of that relation this step works out.
10
+ *
11
+ * Named in the PREMISE relation's own vocabulary, so `n` for `n = c * V`.
12
+ */
13
+ readonly solveFor: string;
14
+ /**
15
+ * How the premise relation's variables are filled, as premise name to derivation name.
16
+ *
17
+ * The two vocabularies differ on purpose: a dilution talks about `c1` and `c2`, and the relation
18
+ * it leans on only knows `c`. Spelling the mapping out is what lets one relation be reused at
19
+ * both ends of an argument.
20
+ */
21
+ readonly using: Readonly<Record<string, string>>;
22
+ /** What the result is called from here on. */
23
+ readonly gives: string;
24
+ /** Why this step is allowed. The sentence a learner actually needs. */
25
+ readonly because: string;
26
+ }
27
+ type DerivationKind = 'definition' | 'derived' | 'measured';
28
+ interface Derivation {
29
+ readonly kind: DerivationKind;
30
+ /** The argument in one sentence. */
31
+ readonly summary: string;
32
+ /** What is held fixed, which is usually the whole reason a derivation works. */
33
+ readonly invariant?: string;
34
+ /** The chain, for a derived relation. Empty for a definition or a measurement. */
35
+ readonly steps?: readonly DerivationStep[];
36
+ /** Which variable of the TARGET relation the chain arrives at. */
37
+ readonly arrivesAt?: string;
38
+ /** What was observed, for a measured relation. */
39
+ readonly evidence?: string;
40
+ }
41
+ /**
42
+ * Walk a derivation and compute its result from the inputs, the long way round.
43
+ *
44
+ * Each step solves one premise relation and adds its answer to the scope, so later steps can use
45
+ * it. The value returned is whatever the last step produced.
46
+ */
47
+ declare function deriveValue(derivation: Derivation, inputs: Readonly<Record<string, number>>): number;
48
+ interface DerivationCheck {
49
+ readonly agrees: boolean;
50
+ /** The largest relative difference found across the samples. */
51
+ readonly worstError: number;
52
+ /** The inputs that produced it, for a failure worth reading. */
53
+ readonly worstAt?: Readonly<Record<string, number>>;
54
+ }
55
+ /**
56
+ * Check a derivation by computing the answer both ways over a set of inputs.
57
+ *
58
+ * The target relation gives the short answer, the chain gives the long one, and a sound derivation
59
+ * makes them the same number. Anything else means the argument does not actually reach the formula
60
+ * it claims to reach, which is a thing a paragraph of prose can hide indefinitely.
61
+ *
62
+ * The samples are supplied rather than generated, so a check reads as a list of cases and a failure
63
+ * names the one that broke.
64
+ */
65
+ declare function checkDerivation(target: Relation, derivation: Derivation, samples: readonly Readonly<Record<string, number>>[], tolerance?: number): DerivationCheck;
66
+ /**
67
+ * The derivation as lines of reasoning, for a lesson to show.
68
+ *
69
+ * Returns the sentences and not a rendered block, because how it is laid out is a decision for
70
+ * whatever is displaying it.
71
+ */
72
+ declare function explain(derivation: Derivation): string[];
73
+ //#endregion
74
+ export { Derivation, DerivationCheck, DerivationKind, DerivationStep, checkDerivation, deriveValue, explain };
@@ -0,0 +1,73 @@
1
+ //#region src/relation/derive.ts
2
+ /**
3
+ * Walk a derivation and compute its result from the inputs, the long way round.
4
+ *
5
+ * Each step solves one premise relation and adds its answer to the scope, so later steps can use
6
+ * it. The value returned is whatever the last step produced.
7
+ */
8
+ function deriveValue(derivation, inputs) {
9
+ if (!derivation.steps || derivation.steps.length === 0) throw new Error(`this ${derivation.kind} has no chain to walk: only a derived relation can be computed step by step`);
10
+ const scope = { ...inputs };
11
+ let last = 0;
12
+ for (const step of derivation.steps) {
13
+ const given = {};
14
+ for (const [premiseName, ourName] of Object.entries(step.using)) {
15
+ const value = scope[ourName];
16
+ if (value === void 0) throw new Error(`the step giving "${step.gives}" needs "${ourName}", which no earlier step produced and the inputs do not contain`);
17
+ given[premiseName] = value;
18
+ }
19
+ last = step.relation().solve(given).value;
20
+ scope[step.gives] = last;
21
+ }
22
+ return last;
23
+ }
24
+ /**
25
+ * Check a derivation by computing the answer both ways over a set of inputs.
26
+ *
27
+ * The target relation gives the short answer, the chain gives the long one, and a sound derivation
28
+ * makes them the same number. Anything else means the argument does not actually reach the formula
29
+ * it claims to reach, which is a thing a paragraph of prose can hide indefinitely.
30
+ *
31
+ * The samples are supplied rather than generated, so a check reads as a list of cases and a failure
32
+ * names the one that broke.
33
+ */
34
+ function checkDerivation(target, derivation, samples, tolerance = 1e-9) {
35
+ if (!derivation.arrivesAt) throw new Error("a derivation that is checked must say which variable of the target it arrives at");
36
+ let worstError = 0;
37
+ let worstAt;
38
+ for (const sample of samples) {
39
+ const theLongWay = deriveValue(derivation, sample);
40
+ const theShortWay = target.solve({ ...sample }).value;
41
+ const scale = Math.max(Math.abs(theShortWay), 1e-12);
42
+ const error = Math.abs(theLongWay - theShortWay) / scale;
43
+ if (error > worstError) {
44
+ worstError = error;
45
+ worstAt = sample;
46
+ }
47
+ }
48
+ return worstError <= tolerance ? {
49
+ agrees: true,
50
+ worstError
51
+ } : {
52
+ agrees: false,
53
+ worstError,
54
+ ...worstAt ? { worstAt } : {}
55
+ };
56
+ }
57
+ /**
58
+ * The derivation as lines of reasoning, for a lesson to show.
59
+ *
60
+ * Returns the sentences and not a rendered block, because how it is laid out is a decision for
61
+ * whatever is displaying it.
62
+ */
63
+ function explain(derivation) {
64
+ const lines = [derivation.summary];
65
+ if (derivation.invariant) lines.push(`What stays fixed: ${derivation.invariant}`);
66
+ if (derivation.kind === "measured" && derivation.evidence) lines.push(`This one is measured, not derived. ${derivation.evidence}`);
67
+ if (derivation.kind === "definition") lines.push("This one is a definition. There is nothing underneath it to derive.");
68
+ for (const step of derivation.steps ?? []) lines.push(`${step.relation().title}, solved for ${step.solveFor}: ${step.because}`);
69
+ return lines;
70
+ }
71
+
72
+ //#endregion
73
+ export { checkDerivation, deriveValue, explain };
@@ -0,0 +1,56 @@
1
+ import { Quantity } from "../quantity/index.mjs";
2
+ import { Worked } from "../core/worked.mjs";
3
+ import { Derivation, DerivationCheck, DerivationKind, DerivationStep, checkDerivation, deriveValue, explain } from "./derive.mjs";
4
+
5
+ //#region src/relation/index.d.ts
6
+ /** A value supplied to `solve`: a bare number IN THE DECLARED UNIT, or a quantity in any unit. */
7
+ type Given = number | Quantity;
8
+ interface Solved {
9
+ /** The variable that was solved for. */
10
+ readonly name: string;
11
+ /** Its value, in the unit the relation declared for it. */
12
+ readonly value: number;
13
+ readonly unit: string;
14
+ readonly quantity: Quantity;
15
+ }
16
+ interface RelationSpec {
17
+ /** `'n = c * V'`. Exactly one `=`. */
18
+ readonly equation: string;
19
+ /** Unit for every variable in the equation. A missing one is an error, not a guess. */
20
+ readonly units: Readonly<Record<string, string>>;
21
+ /** Shown instead of the raw equation in worked steps. Defaults to the equation. */
22
+ readonly title?: string;
23
+ }
24
+ declare class Relation {
25
+ readonly equation: string;
26
+ readonly title: string;
27
+ readonly units: Readonly<Record<string, string>>;
28
+ readonly variables: readonly string[];
29
+ private readonly left;
30
+ private readonly right;
31
+ private readonly dims;
32
+ private readonly isolated;
33
+ constructor(spec: RelationSpec);
34
+ /** The declared unit of a variable. */
35
+ unitOf(name: string): string;
36
+ /** Numeric values in declared units, converting any Quantity that was passed in. */
37
+ private normalise;
38
+ /** The one variable of the relation that `given` does not supply. */
39
+ private unknownOf;
40
+ private expressionFor;
41
+ /** Solve for whichever variable was left out of `given`. */
42
+ solve(given: Readonly<Record<string, Given>>): Solved;
43
+ /** Solve for a named variable, ignoring any value supplied for it. */
44
+ solveFor(target: string, given: Readonly<Record<string, Given>>): Solved;
45
+ /**
46
+ * The worked substitution, for a lesson's derivation.
47
+ *
48
+ * Three lines: the relation, the relation rearranged for the unknown, and the substitution with
49
+ * the answer. Every number shown came from `given`, which is the property that makes a generated
50
+ * derivation trustworthy in a way a hand-written one is not.
51
+ */
52
+ steps(given: Readonly<Record<string, Given>>, sf?: number): Worked;
53
+ }
54
+ declare const relation: (equation: string, units: Readonly<Record<string, string>>, title?: string) => Relation;
55
+ //#endregion
56
+ export { type Derivation, type DerivationCheck, type DerivationKind, type DerivationStep, Given, Relation, RelationSpec, Solved, checkDerivation, deriveValue, explain, relation };