@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,150 @@
1
+ import { fromMinor, toMinor } from "../accounting/precision.mjs";
2
+
3
+ //#region src/finance/management-accounting/variances.ts
4
+ const DEFAULT_POLICY = { decimalPlaces: 2 };
5
+ function analyzeCostVariances(facts, policy = DEFAULT_POLICY) {
6
+ const diagnostics = [];
7
+ if ([
8
+ facts.actualOutputUnits,
9
+ facts.material.standardQuantityPerUnit,
10
+ facts.material.standardPricePerUnit,
11
+ facts.material.actualQuantity,
12
+ facts.material.actualPricePerUnit,
13
+ facts.labour.standardHoursPerUnit,
14
+ facts.labour.standardRatePerHour,
15
+ facts.labour.actualHours,
16
+ facts.labour.actualRatePerHour,
17
+ facts.variableOverhead.standardRatePerHour,
18
+ facts.variableOverhead.actualRatePerHour,
19
+ facts.fixedOverhead.budgeted,
20
+ facts.fixedOverhead.actual
21
+ ].some((value) => !Number.isFinite(value) || value < 0)) diagnostics.push({
22
+ code: "invalid-input",
23
+ severity: "error",
24
+ message: "Variance inputs must be finite and non-negative."
25
+ });
26
+ if (!Number.isFinite(facts.fixedOverhead.normalCapacityHours) || facts.fixedOverhead.normalCapacityHours <= 0) diagnostics.push({
27
+ code: "invalid-input",
28
+ severity: "error",
29
+ message: "Normal capacity hours must be finite and positive."
30
+ });
31
+ if (diagnostics.length > 0) return emptyResult(diagnostics);
32
+ const standardQuantity = facts.actualOutputUnits * facts.material.standardQuantityPerUnit;
33
+ const standardHours = facts.actualOutputUnits * facts.labour.standardHoursPerUnit;
34
+ const variance = (amount) => {
35
+ const rounded = money(amount, policy);
36
+ return {
37
+ amount: Math.abs(rounded),
38
+ outcome: rounded > 0 ? "favorable" : rounded < 0 ? "adverse" : "none"
39
+ };
40
+ };
41
+ const signed = (item) => item.outcome === "favorable" ? item.amount : item.outcome === "adverse" ? -item.amount : 0;
42
+ const combine = (...items) => variance(items.reduce((sum, item) => sum + signed(item), 0));
43
+ const materialPrice = variance(facts.material.actualQuantity * (facts.material.standardPricePerUnit - facts.material.actualPricePerUnit));
44
+ const materialUsage = variance(facts.material.standardPricePerUnit * (standardQuantity - facts.material.actualQuantity));
45
+ const labourRate = variance(facts.labour.actualHours * (facts.labour.standardRatePerHour - facts.labour.actualRatePerHour));
46
+ const labourEfficiency = variance(facts.labour.standardRatePerHour * (standardHours - facts.labour.actualHours));
47
+ const variableExpenditure = variance(facts.labour.actualHours * (facts.variableOverhead.standardRatePerHour - facts.variableOverhead.actualRatePerHour));
48
+ const variableEfficiency = variance(facts.variableOverhead.standardRatePerHour * (standardHours - facts.labour.actualHours));
49
+ const fixedExpenditure = variance(facts.fixedOverhead.budgeted - facts.fixedOverhead.actual);
50
+ const fixedVolume = variance(standardHours * (facts.fixedOverhead.budgeted / facts.fixedOverhead.normalCapacityHours) - facts.fixedOverhead.budgeted);
51
+ const materialTotal = combine(materialPrice, materialUsage);
52
+ const labourTotal = combine(labourRate, labourEfficiency);
53
+ const variableTotal = combine(variableExpenditure, variableEfficiency);
54
+ const fixedTotal = combine(fixedExpenditure, fixedVolume);
55
+ const totalCostVariance = combine(materialTotal, labourTotal, variableTotal, fixedTotal);
56
+ const trace = [
57
+ {
58
+ id: "variance:material-price",
59
+ kind: "derive",
60
+ rule: "Material price variance = actual quantity × (standard price − actual price). Positive is favorable.",
61
+ working: `${facts.material.actualQuantity} × (${facts.material.standardPricePerUnit} − ${facts.material.actualPricePerUnit})`,
62
+ result: signed(materialPrice)
63
+ },
64
+ {
65
+ id: "variance:material-usage",
66
+ kind: "derive",
67
+ rule: "Material usage variance = standard price × (standard quantity for output − actual quantity). Positive is favorable.",
68
+ working: `${facts.material.standardPricePerUnit} × (${standardQuantity} − ${facts.material.actualQuantity})`,
69
+ result: signed(materialUsage)
70
+ },
71
+ {
72
+ id: "variance:labour-rate",
73
+ kind: "derive",
74
+ rule: "Labour rate variance = actual hours × (standard rate − actual rate). Positive is favorable.",
75
+ working: `${facts.labour.actualHours} × (${facts.labour.standardRatePerHour} − ${facts.labour.actualRatePerHour})`,
76
+ result: signed(labourRate)
77
+ },
78
+ {
79
+ id: "variance:labour-efficiency",
80
+ kind: "derive",
81
+ rule: "Labour efficiency variance = standard rate × (standard hours for output − actual hours). Positive is favorable.",
82
+ working: `${facts.labour.standardRatePerHour} × (${standardHours} − ${facts.labour.actualHours})`,
83
+ result: signed(labourEfficiency)
84
+ }
85
+ ];
86
+ return {
87
+ completed: true,
88
+ standardQuantity,
89
+ standardHours,
90
+ material: {
91
+ price: materialPrice,
92
+ usage: materialUsage,
93
+ total: materialTotal
94
+ },
95
+ labour: {
96
+ rate: labourRate,
97
+ efficiency: labourEfficiency,
98
+ total: labourTotal
99
+ },
100
+ variableOverhead: {
101
+ expenditure: variableExpenditure,
102
+ efficiency: variableEfficiency,
103
+ total: variableTotal
104
+ },
105
+ fixedOverhead: {
106
+ expenditure: fixedExpenditure,
107
+ volume: fixedVolume,
108
+ total: fixedTotal
109
+ },
110
+ totalCostVariance,
111
+ diagnostics,
112
+ trace
113
+ };
114
+ }
115
+ const money = (value, policy) => fromMinor(toMinor(value, policy), policy);
116
+ const zero = {
117
+ amount: 0,
118
+ outcome: "none"
119
+ };
120
+ const emptyResult = (diagnostics) => ({
121
+ completed: false,
122
+ standardQuantity: 0,
123
+ standardHours: 0,
124
+ material: {
125
+ price: zero,
126
+ usage: zero,
127
+ total: zero
128
+ },
129
+ labour: {
130
+ rate: zero,
131
+ efficiency: zero,
132
+ total: zero
133
+ },
134
+ variableOverhead: {
135
+ expenditure: zero,
136
+ efficiency: zero,
137
+ total: zero
138
+ },
139
+ fixedOverhead: {
140
+ expenditure: zero,
141
+ volume: zero,
142
+ total: zero
143
+ },
144
+ totalCostVariance: zero,
145
+ diagnostics,
146
+ trace: []
147
+ });
148
+
149
+ //#endregion
150
+ export { analyzeCostVariances };
package/dist/index.d.mts CHANGED
@@ -12,6 +12,12 @@ import { IconName, ToolIcon } from "./builder/icons.mjs";
12
12
  import { AUTHORING_TOOLS, CIRCLE, DELETE, GEOMETRY_TOOLS, INTERSECT, LINE, MEASURE, MIDPOINT, NOTE, POINT, SCALAR, SEGMENT, SELECT, Tool, ToolCtx } from "./builder/tools.mjs";
13
13
  import { SceneBuilder, SceneBuilderProps } from "./builder/SceneBuilder.mjs";
14
14
  import { Palette, PaletteProps } from "./builder/Palette.mjs";
15
+ import { BinOp, Node, compileNode, evaluate, freeVars } from "./math/ast.mjs";
16
+ import { parse as parse$1 } from "./math/parse.mjs";
17
+ import { definiteIntegral, differentiate, integrate, simplify } from "./math/calculus.mjs";
18
+ import { CompiledFn, compile } from "./math/compile.mjs";
19
+ import { toLatex as toLatex$1 } from "./math/latex.mjs";
20
+ import { CompiledExpr, ExprError, ExprResult, compileExpr } from "./math/expr.mjs";
15
21
  import { CoordsContext, DragOverlayContext, StageRefContext, useCoords, useDragOverlay, useStageRef } from "./core/context.mjs";
16
22
  import { ClockProvider, ClockProviderProps, FrameDriver, FrameInfo, useFrameLoop } from "./core/clock.mjs";
17
23
  import { Learner, LearnerProvider, LearnerResult, PriorAttempts, useLearner } from "./core/learner.mjs";
@@ -41,12 +47,6 @@ import { CURRENT_SCHEMA_VERSION, emptyDoc, migrate, parse, serialize } from "./s
41
47
  import { InstanceState, SceneStore } from "./scene/store.mjs";
42
48
  import { Scene, SceneProps } from "./scene/Scene.mjs";
43
49
  import { RenderOpts, renderElements } from "./scene/render.mjs";
44
- import { BinOp, Node, compileNode, evaluate, freeVars } from "./math/ast.mjs";
45
- import { parse as parse$1 } from "./math/parse.mjs";
46
- import { definiteIntegral, differentiate, integrate, simplify } from "./math/calculus.mjs";
47
- import { CompiledFn, compile } from "./math/compile.mjs";
48
- import { toLatex as toLatex$1 } from "./math/latex.mjs";
49
- import { CompiledExpr, ExprError, ExprResult, compileExpr } from "./math/index.mjs";
50
50
  import { BinOp as BinOp$1, LNode, evalBool, freeVars as freeVars$1 } from "./logic/ast.mjs";
51
51
  import { parseLogic } from "./logic/parse.mjs";
52
52
  import { Classification, TruthRow, TruthTable, classify, equivalent, toCNF, toDNF, truthTable } from "./logic/table.mjs";
package/dist/index.mjs CHANGED
@@ -31,7 +31,7 @@ import { parse as parse$1 } from "./math/parse.mjs";
31
31
  import { definiteIntegral, differentiate, integrate, simplify } from "./math/calculus.mjs";
32
32
  import { compile } from "./math/compile.mjs";
33
33
  import { toLatex as toLatex$1 } from "./math/latex.mjs";
34
- import { compileExpr } from "./math/index.mjs";
34
+ import { compileExpr } from "./math/expr.mjs";
35
35
  import { EVALUATORS } from "./scene/evaluators.mjs";
36
36
  import { resolve } from "./scene/resolve.mjs";
37
37
  import { applyCommand, collectRemoved, inverse } from "./scene/commands.mjs";
@@ -0,0 +1,61 @@
1
+ import { Node } from "./ast.mjs";
2
+
3
+ //#region src/math/analysis.d.ts
4
+ type Fn1 = (x: number) => number;
5
+ /** A straight line y = m·x + c, with the point it was taken at and an evaluator. */
6
+ interface Line {
7
+ m: number;
8
+ c: number;
9
+ at: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ f: Fn1;
14
+ }
15
+ /**
16
+ * Real roots of f on [a,b]. Two passes so it doesn't miss the roots students do:
17
+ * 1. sign-change brackets refined by BISECTION (odd-multiplicity / crossings);
18
+ * 2. local minima of |f| polished by NEWTON, accepted only if |f| really drops
19
+ * to ~0 — this recovers TANGENT / double roots (e.g. x² at 0) that never
20
+ * change sign. False minima (a parabola that never reaches 0) are rejected
21
+ * by the accept tolerance, so no phantom roots.
22
+ */
23
+ declare function roots(f: Fn1, a: number, b: number, opts?: {
24
+ steps?: number;
25
+ tol?: number;
26
+ }): number[];
27
+ /** Points where f and g meet on [a,b]. */
28
+ declare function intersections(f: Fn1, g: Fn1, a: number, b: number, opts?: {
29
+ steps?: number;
30
+ tol?: number;
31
+ }): {
32
+ x: number;
33
+ y: number;
34
+ }[];
35
+ /** Exact tangent line to `ast` at x = x0 (params baked in via `scope`). */
36
+ declare function tangentAt(ast: Node, x0: number, varName?: string, params?: Record<string, number>): Line | null;
37
+ /** Normal line to `ast` at x = x0 (⟂ the tangent). Null if the tangent is horizontal. */
38
+ declare function normalAt(ast: Node, x0: number, varName?: string, params?: Record<string, number>): Line | null;
39
+ /**
40
+ * Composite-Simpson definite integral ∫_a^b f dx, on a NUMERIC function.
41
+ *
42
+ * Error O(h⁴) against O(h) for a Riemann sum, so at n≈1000 it is accurate to near machine
43
+ * precision for a smooth integrand and serves as the reference value a Riemann sum converges
44
+ * toward. `n` is forced even, as the rule requires. Not adaptive: a singularity inside [a, b] is
45
+ * not detected, which is why the callers in this file (`areaBetween`) split at the crossings first.
46
+ *
47
+ * Named `quadrature` because `calculus.ts` beside it exports `integrate`, which integrates an AST
48
+ * SYMBOLICALLY: different argument type, different return type, different meaning. (`simpson`
49
+ * would become a lie the moment the rule changed.) The single implementation, after two copies of
50
+ * it were found in labs; see `KERNEL-CONTRACT.md` §7.
51
+ */
52
+ declare function quadrature(f: Fn1, a: number, b: number, n?: number): number;
53
+ /**
54
+ * Geometric area between f and g over [a,b]. SPLITS at every crossing so the
55
+ * pieces where g > f don't cancel the pieces where f > g (which a single
56
+ * |∫(f−g)| would). Sums |∫| over each sub-interval — the area an exam actually
57
+ * wants.
58
+ */
59
+ declare function areaBetween(f: Fn1, g: Fn1, a: number, b: number, n?: number): number;
60
+ //#endregion
61
+ export { Fn1, Line, areaBetween, intersections, normalAt, quadrature, roots, tangentAt };
@@ -0,0 +1,187 @@
1
+ import { evaluate } from "./ast.mjs";
2
+ import { differentiate } from "./calculus.mjs";
3
+
4
+ //#region src/math/analysis.ts
5
+ /**
6
+ * analysis, the NUMERIC layer over this package's symbolic engine: the half of calculus that needs
7
+ * a number rather than an expression. `calculus.ts` differentiates and integrates an AST exactly;
8
+ * this file finds roots, intersections, tangents, normals and areas, which in general have no
9
+ * closed form at all.
10
+ *
11
+ * Everything works on a compiled scalar `Fn1 = (x) => number` (params already baked into the
12
+ * closure) plus, for exact tangents, the parsed `Node` AST. Pure: no React, no pixels.
13
+ *
14
+ * Methods, and why each is safe:
15
+ * • roots, bisection on sign changes PLUS Newton at local minima of |f|, so tangent (even
16
+ * multiplicity) roots are found and poles are rejected. See the docblock on `roots`.
17
+ * • tangents/normals, EXACT: the AST is differentiated symbolically, then evaluated. No
18
+ * finite-difference error in the gradient a lesson shows.
19
+ * • quadrature, composite Simpson, error O(h⁴).
20
+ *
21
+ * Units: none. These are pure numbers on a pure function.
22
+ */
23
+ function pushUnique(out, x, tol) {
24
+ if (!out.some((p) => Math.abs(p - x) <= tol)) out.push(x);
25
+ }
26
+ /** Newton's method from x0 using a central-difference derivative (we only hold
27
+ * the numeric f, not its AST). Returns the polished root, or null on a flat
28
+ * derivative / divergence. Used to recover tangent (even-multiplicity) roots a
29
+ * sign-change scan can't see. */
30
+ function newton(f, x0, tol) {
31
+ let x = x0;
32
+ for (let k = 0; k < 40; k++) {
33
+ const fx = f(x);
34
+ if (!Number.isFinite(fx)) return null;
35
+ if (Math.abs(fx) <= tol) return x;
36
+ const h = Math.max(1e-7, Math.abs(x) * 1e-7);
37
+ const d = (f(x + h) - f(x - h)) / (2 * h);
38
+ if (!Number.isFinite(d) || Math.abs(d) < 1e-13) return null;
39
+ const nx = x - fx / d;
40
+ if (!Number.isFinite(nx)) return null;
41
+ if (Math.abs(nx - x) <= tol) return nx;
42
+ x = nx;
43
+ }
44
+ return Math.abs(f(x)) <= tol ? x : null;
45
+ }
46
+ /**
47
+ * Real roots of f on [a,b]. Two passes so it doesn't miss the roots students do:
48
+ * 1. sign-change brackets refined by BISECTION (odd-multiplicity / crossings);
49
+ * 2. local minima of |f| polished by NEWTON, accepted only if |f| really drops
50
+ * to ~0 — this recovers TANGENT / double roots (e.g. x² at 0) that never
51
+ * change sign. False minima (a parabola that never reaches 0) are rejected
52
+ * by the accept tolerance, so no phantom roots.
53
+ */
54
+ function roots(f, a, b, opts = {}) {
55
+ const steps = opts.steps ?? 1e3;
56
+ const tol = opts.tol ?? 1e-9;
57
+ const grid = (b - a) / steps;
58
+ const out = [];
59
+ const xs = [], fs = [];
60
+ for (let i = 0; i <= steps; i++) {
61
+ const x = a + grid * i;
62
+ xs.push(x);
63
+ fs.push(f(x));
64
+ }
65
+ let maxAbs = 0;
66
+ for (const v of fs) if (Number.isFinite(v)) maxAbs = Math.max(maxAbs, Math.abs(v));
67
+ const acceptTol = 1e-7 * (1 + maxAbs);
68
+ for (let i = 1; i <= steps; i++) {
69
+ const fPrev = fs[i - 1], fx = fs[i];
70
+ if (!Number.isFinite(fPrev) || !Number.isFinite(fx)) continue;
71
+ if (fPrev === 0) {
72
+ pushUnique(out, xs[i - 1], grid);
73
+ continue;
74
+ }
75
+ if (fPrev * fx < 0) {
76
+ let lo = xs[i - 1], hi = xs[i], flo = fPrev;
77
+ for (let k = 0; k < 80 && hi - lo > tol; k++) {
78
+ const mid = (lo + hi) / 2;
79
+ const fm = f(mid);
80
+ if (!Number.isFinite(fm)) break;
81
+ if (flo * fm <= 0) hi = mid;
82
+ else {
83
+ lo = mid;
84
+ flo = fm;
85
+ }
86
+ }
87
+ const mid = (lo + hi) / 2;
88
+ if (Math.abs(f(mid)) <= acceptTol) pushUnique(out, mid, grid);
89
+ }
90
+ }
91
+ for (let i = 1; i < steps; i++) {
92
+ const p = fs[i - 1], c = fs[i], q = fs[i + 1];
93
+ if (!Number.isFinite(p) || !Number.isFinite(c) || !Number.isFinite(q)) continue;
94
+ if (Math.abs(c) <= Math.abs(p) && Math.abs(c) <= Math.abs(q) && Math.abs(c) < .05 * (1 + maxAbs)) {
95
+ const r = newton(f, xs[i], tol);
96
+ if (r != null && r >= a - grid && r <= b + grid && Math.abs(f(r)) <= acceptTol) pushUnique(out, r, grid);
97
+ }
98
+ }
99
+ out.sort((u, v) => u - v);
100
+ return out;
101
+ }
102
+ /** Points where f and g meet on [a,b]. */
103
+ function intersections(f, g, a, b, opts) {
104
+ return roots((x) => f(x) - g(x), a, b, opts).map((x) => ({
105
+ x,
106
+ y: f(x)
107
+ }));
108
+ }
109
+ /** Exact tangent line to `ast` at x = x0 (params baked in via `scope`). */
110
+ function tangentAt(ast, x0, varName = "x", params = {}) {
111
+ const d = differentiate(ast, varName);
112
+ if (!d) return null;
113
+ const m = evaluate(d, {
114
+ ...params,
115
+ [varName]: x0
116
+ });
117
+ const y0 = evaluate(ast, {
118
+ ...params,
119
+ [varName]: x0
120
+ });
121
+ if (!Number.isFinite(m) || !Number.isFinite(y0)) return null;
122
+ const c = y0 - m * x0;
123
+ return {
124
+ m,
125
+ c,
126
+ at: {
127
+ x: x0,
128
+ y: y0
129
+ },
130
+ f: (x) => m * x + c
131
+ };
132
+ }
133
+ /** Normal line to `ast` at x = x0 (⟂ the tangent). Null if the tangent is horizontal. */
134
+ function normalAt(ast, x0, varName = "x", params = {}) {
135
+ const t = tangentAt(ast, x0, varName, params);
136
+ if (!t || t.m === 0) return null;
137
+ const m = -1 / t.m;
138
+ const c = t.at.y - m * t.at.x;
139
+ return {
140
+ m,
141
+ c,
142
+ at: t.at,
143
+ f: (x) => m * x + c
144
+ };
145
+ }
146
+ /**
147
+ * Composite-Simpson definite integral ∫_a^b f dx, on a NUMERIC function.
148
+ *
149
+ * Error O(h⁴) against O(h) for a Riemann sum, so at n≈1000 it is accurate to near machine
150
+ * precision for a smooth integrand and serves as the reference value a Riemann sum converges
151
+ * toward. `n` is forced even, as the rule requires. Not adaptive: a singularity inside [a, b] is
152
+ * not detected, which is why the callers in this file (`areaBetween`) split at the crossings first.
153
+ *
154
+ * Named `quadrature` because `calculus.ts` beside it exports `integrate`, which integrates an AST
155
+ * SYMBOLICALLY: different argument type, different return type, different meaning. (`simpson`
156
+ * would become a lie the moment the rule changed.) The single implementation, after two copies of
157
+ * it were found in labs; see `KERNEL-CONTRACT.md` §7.
158
+ */
159
+ function quadrature(f, a, b, n = 1e3) {
160
+ if (a === b) return 0;
161
+ const m = Math.max(2, Math.ceil(n / 2) * 2);
162
+ const h = (b - a) / m;
163
+ let sum = f(a) + f(b);
164
+ for (let i = 1; i < m; i++) sum += (i % 2 === 1 ? 4 : 2) * f(a + i * h);
165
+ return sum * h / 3;
166
+ }
167
+ /**
168
+ * Geometric area between f and g over [a,b]. SPLITS at every crossing so the
169
+ * pieces where g > f don't cancel the pieces where f > g (which a single
170
+ * |∫(f−g)| would). Sums |∫| over each sub-interval — the area an exam actually
171
+ * wants.
172
+ */
173
+ function areaBetween(f, g, a, b, n = 1e3) {
174
+ const d = (x) => f(x) - g(x);
175
+ const cuts = [
176
+ a,
177
+ ...roots(d, a, b).filter((x) => x > a + 1e-9 && x < b - 1e-9).sort((u, v) => u - v),
178
+ b
179
+ ];
180
+ const per = Math.max(20, Math.round(n / Math.max(1, cuts.length - 1)));
181
+ let area = 0;
182
+ for (let i = 0; i < cuts.length - 1; i++) area += Math.abs(quadrature(d, cuts[i], cuts[i + 1], per));
183
+ return area;
184
+ }
185
+
186
+ //#endregion
187
+ export { areaBetween, intersections, normalAt, quadrature, roots, tangentAt };
@@ -0,0 +1,50 @@
1
+ //#region src/math/answer-check.d.ts
2
+ /**
3
+ * answer-check, the "is the student right?" layer, built on the expr engine beside it. Two modes,
4
+ * the ones exams need:
5
+ *
6
+ * • NUMBER — value within tolerance, parsed so `pi/2` and `2*sqrt(5)` count.
7
+ * • EXPRESSION — any algebraically EQUIVALENT form accepted, checked BOTH symbolically
8
+ * (simplify(student − answer) → 0) AND numerically by sampling, so
9
+ * `(x+1)(x+2)` ≡ `x^2+3x+2`.
10
+ *
11
+ * Both passes run because neither is sufficient alone: the simplifier cannot collapse every
12
+ * equivalent pair, and sampling alone would accept two expressions that happen to agree on the
13
+ * sample points. Symbolic first, numeric as the fallback, and a minimum count of agreeing FINITE
14
+ * samples so a pair that is undefined everywhere in the window cannot pass by default.
15
+ *
16
+ * Tolerances are relative, not absolute: a 1% window on a quantity of order 10⁵ is not the same
17
+ * marking scheme as a 1% window on 0.3, and only one of those is what an exam means.
18
+ *
19
+ * Pure: no React, no pixels.
20
+ */
21
+ /** Evaluate a numeric answer string (`3.14`, `pi/2`, `2*sqrt(5)`) → number (NaN if invalid). */
22
+ declare function parseValue(raw: string): number;
23
+ declare function normalizeMathInput(raw: string): string;
24
+ /** Numeric match with a relative-ish tolerance (default ~1% of scale). */
25
+ declare function checkNumber(student: number, value: number, tol?: number): boolean;
26
+ interface ExprCheckOpts {
27
+ /** Variables to sample (defaults to the union of both sides' free vars). */
28
+ vars?: string[];
29
+ /** Sampling domain for the numeric pass. */
30
+ domain?: [number, number];
31
+ tol?: number;
32
+ samples?: number;
33
+ }
34
+ /** True if `student` is algebraically equivalent to `answer` (symbolic OR numeric). */
35
+ declare function checkExpression(student: string, answer: string, opts?: ExprCheckOpts): boolean;
36
+ type AnswerSpec = {
37
+ kind: 'number';
38
+ value: number;
39
+ tol?: number;
40
+ } | {
41
+ kind: 'expression';
42
+ value: string;
43
+ vars?: string[];
44
+ domain?: [number, number];
45
+ tol?: number;
46
+ };
47
+ /** Check a raw student string against an authored answer spec. */
48
+ declare function checkAnswer(spec: AnswerSpec, raw: string): boolean;
49
+ //#endregion
50
+ export { AnswerSpec, ExprCheckOpts, checkAnswer, checkExpression, checkNumber, normalizeMathInput, parseValue };
@@ -0,0 +1,106 @@
1
+ import { parse } from "./parse.mjs";
2
+ import { simplify } from "./calculus.mjs";
3
+ import { compileExpr } from "./expr.mjs";
4
+
5
+ //#region src/math/answer-check.ts
6
+ /**
7
+ * answer-check, the "is the student right?" layer, built on the expr engine beside it. Two modes,
8
+ * the ones exams need:
9
+ *
10
+ * • NUMBER — value within tolerance, parsed so `pi/2` and `2*sqrt(5)` count.
11
+ * • EXPRESSION — any algebraically EQUIVALENT form accepted, checked BOTH symbolically
12
+ * (simplify(student − answer) → 0) AND numerically by sampling, so
13
+ * `(x+1)(x+2)` ≡ `x^2+3x+2`.
14
+ *
15
+ * Both passes run because neither is sufficient alone: the simplifier cannot collapse every
16
+ * equivalent pair, and sampling alone would accept two expressions that happen to agree on the
17
+ * sample points. Symbolic first, numeric as the fallback, and a minimum count of agreeing FINITE
18
+ * samples so a pair that is undefined everywhere in the window cannot pass by default.
19
+ *
20
+ * Tolerances are relative, not absolute: a 1% window on a quantity of order 10⁵ is not the same
21
+ * marking scheme as a 1% window on 0.3, and only one of those is what an exam means.
22
+ *
23
+ * Pure: no React, no pixels.
24
+ */
25
+ /** Compile, returning the usable form or null (never the error union). */
26
+ function tryCompile(src) {
27
+ const c = compileExpr(src);
28
+ if (c.error !== void 0) return null;
29
+ return c;
30
+ }
31
+ /** Evaluate a numeric answer string (`3.14`, `pi/2`, `2*sqrt(5)`) → number (NaN if invalid). */
32
+ function parseValue(raw) {
33
+ const c = tryCompile(normalizeMathInput(raw));
34
+ return c ? c.fn({}) : NaN;
35
+ }
36
+ /**
37
+ * Make exam-natural input parse: accept implicit multiplication (`2x` → `2*x`,
38
+ * `)(` → `)*(`) and a leading `y =` (`y = 2x − 3` → `2*x - 3`). Conservative ,
39
+ * never inserts `*` before `(` after a letter, so function calls like `sin(x)`
40
+ * survive. Unicode minus → ascii.
41
+ */
42
+ const SUPERSCRIPT = {
43
+ "⁰": "0",
44
+ "¹": "1",
45
+ "²": "2",
46
+ "³": "3",
47
+ "⁴": "4",
48
+ "⁵": "5",
49
+ "⁶": "6",
50
+ "⁷": "7",
51
+ "⁸": "8",
52
+ "⁹": "9"
53
+ };
54
+ function normalizeMathInput(raw) {
55
+ let s = raw.trim().replace(/−/g, "-").replace(/×/g, "*").replace(/÷/g, "/");
56
+ s = s.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/g, (m) => "^" + [...m].map((ch) => SUPERSCRIPT[ch]).join(""));
57
+ s = s.replace(/\*\*/g, "^");
58
+ s = s.replace(/\s+/g, "");
59
+ s = s.replace(/^y=/i, "");
60
+ s = s.replace(/(\d)(?![eE][+-]?\d)([a-zA-Z(])/g, "$1*$2");
61
+ s = s.replace(/\)([a-zA-Z0-9(])/g, ")*$1");
62
+ return s;
63
+ }
64
+ /** Numeric match with a relative-ish tolerance (default ~1% of scale). */
65
+ function checkNumber(student, value, tol = .01) {
66
+ if (!Number.isFinite(student) || !Number.isFinite(value)) return false;
67
+ return Math.abs(student - value) <= tol * Math.max(1, Math.abs(value));
68
+ }
69
+ const isZeroNode = (n, eps = 1e-9) => n.type === "num" && Math.abs(n.value) < eps;
70
+ /** True if `student` is algebraically equivalent to `answer` (symbolic OR numeric). */
71
+ function checkExpression(student, answer, opts = {}) {
72
+ const a = tryCompile(normalizeMathInput(student));
73
+ const b = tryCompile(normalizeMathInput(answer));
74
+ if (!a || !b) return false;
75
+ try {
76
+ if (isZeroNode(simplify(parse(`(${normalizeMathInput(student)}) - (${normalizeMathInput(answer)})`)), opts.tol ?? 1e-9)) return true;
77
+ } catch {}
78
+ const vars = opts.vars ?? [...new Set([...a.vars, ...b.vars])];
79
+ const [lo, hi] = opts.domain ?? [-3.3, 3.7];
80
+ const tol = opts.tol ?? 1e-6;
81
+ const samples = opts.samples ?? 32;
82
+ const PHI = .6180339887498949;
83
+ const R2 = .4142135623730951;
84
+ let finite = 0;
85
+ for (let i = 0; i < samples; i++) {
86
+ const scope = {};
87
+ vars.forEach((v, j) => {
88
+ scope[v] = lo + (hi - lo) * (((i + 1) * PHI + (j + 1) * R2) % 1);
89
+ });
90
+ const ya = a.fn(scope);
91
+ const yb = b.fn(scope);
92
+ if (!Number.isFinite(ya) || !Number.isFinite(yb)) continue;
93
+ finite++;
94
+ if (Math.abs(ya - yb) > tol * Math.max(1, Math.abs(ya), Math.abs(yb))) return false;
95
+ }
96
+ return finite >= 5;
97
+ }
98
+ /** Check a raw student string against an authored answer spec. */
99
+ function checkAnswer(spec, raw) {
100
+ if (!raw || !raw.trim()) return false;
101
+ if (spec.kind === "number") return checkNumber(parseValue(raw), spec.value, spec.tol);
102
+ return checkExpression(raw, spec.value, spec);
103
+ }
104
+
105
+ //#endregion
106
+ export { checkAnswer, checkExpression, checkNumber, normalizeMathInput, parseValue };
@@ -4,16 +4,11 @@ import { Node } from "./ast.mjs";
4
4
  /** Exact symbolic derivative, or `null` if a non-differentiable node is present. */
5
5
  declare function differentiate(node: Node, x: string): Node | null;
6
6
  /**
7
- * Exact symbolic antiderivative with respect to `x`, or `null` when this engine cannot do it.
7
+ * Exact symbolic antiderivative, trying the expression as written and then multiplied out.
8
8
  *
9
- * The constant of integration is NOT included. That is deliberate: `+ c` is the single most
10
- * commonly dropped mark in the topic, so it belongs in the lesson's own working where a learner
11
- * has to write it, not silently bolted on by the engine.
12
- *
13
- * Covers the Cambridge P1/P3 toolkit: linearity, the power rule including the `1/x → ln|x|`
14
- * exception, and any of the above composed with a LINEAR inner function. Returns null for
15
- * integration by parts, by non-linear substitution, and partial fractions, so a caller can fall
16
- * back to the numerical `integrate` in `core/numeric` and show area rather than a wrong formula.
9
+ * The second attempt is what makes `∫x(x+1)dx` and `∫(R²−x²)²dx` work: expand distributes, collect
10
+ * turns the resulting repeated factors back into powers, and then the ordinary power rule applies
11
+ * term by term. A single retry, because both passes are idempotent on their own output.
17
12
  */
18
13
  declare function integrate(node: Node, x: string): Node | null;
19
14
  /**