@classytic/stage 0.2.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.
- package/LICENSE +1 -1
- package/README.md +5 -1
- package/dist/_virtual/_rolldown/runtime.mjs +18 -0
- package/dist/assets/index.mjs +0 -1
- package/dist/atomic/aufbau.d.mts +144 -0
- package/dist/atomic/aufbau.mjs +384 -0
- package/dist/atomic/elements.d.mts +67 -0
- package/dist/atomic/elements.mjs +785 -0
- package/dist/atomic/emission.d.mts +112 -0
- package/dist/atomic/emission.mjs +179 -0
- package/dist/atomic/index.d.mts +8 -0
- package/dist/atomic/index.mjs +9 -0
- package/dist/atomic/periodic.d.mts +82 -0
- package/dist/atomic/periodic.mjs +231 -0
- package/dist/atomic/properties.d.mts +100 -0
- package/dist/atomic/properties.mjs +574 -0
- package/dist/atomic/shells.d.mts +137 -0
- package/dist/atomic/shells.mjs +170 -0
- package/dist/atomic/trends.d.mts +148 -0
- package/dist/atomic/trends.mjs +225 -0
- package/dist/builder/Palette.mjs +50 -89
- package/dist/builder/SceneBuilder.mjs +15 -73
- package/dist/chem/chromatography.d.mts +66 -0
- package/dist/chem/chromatography.mjs +63 -0
- package/dist/chem/complex.d.mts +114 -0
- package/dist/chem/complex.mjs +234 -0
- package/dist/chem/cycle.d.mts +75 -0
- package/dist/chem/cycle.mjs +145 -0
- package/dist/chem/equation.d.mts +86 -0
- package/dist/chem/equation.mjs +168 -0
- package/dist/chem/formula.d.mts +90 -0
- package/dist/chem/formula.mjs +201 -0
- package/dist/chem/functional-groups.d.mts +31 -0
- package/dist/chem/functional-groups.mjs +187 -0
- package/dist/chem/hazard.d.mts +94 -0
- package/dist/chem/hazard.mjs +329 -0
- package/dist/chem/index.d.mts +34 -33
- package/dist/chem/index.mjs +34 -28
- package/dist/chem/ionic.d.mts +98 -0
- package/dist/chem/ionic.mjs +156 -0
- package/dist/chem/layout.d.mts +46 -0
- package/dist/chem/layout.mjs +342 -0
- package/dist/chem/lewis.d.mts +79 -0
- package/dist/chem/lewis.mjs +163 -0
- package/dist/chem/molecular-orbital.d.mts +114 -0
- package/dist/chem/molecular-orbital.mjs +201 -0
- package/dist/chem/molecule.d.mts +154 -0
- package/dist/chem/molecule.mjs +282 -0
- package/dist/chem/nmr.d.mts +153 -0
- package/dist/chem/nmr.mjs +165 -0
- package/dist/chem/polymer.d.mts +65 -0
- package/dist/chem/polymer.mjs +179 -0
- package/dist/chem/redox.d.mts +138 -0
- package/dist/chem/redox.mjs +328 -0
- package/dist/chem/relations.d.mts +183 -0
- package/dist/chem/relations.mjs +299 -0
- package/dist/chem/skeleton.d.mts +51 -0
- package/dist/chem/skeleton.mjs +186 -0
- package/dist/chem/solution.d.mts +116 -0
- package/dist/chem/solution.mjs +186 -0
- package/dist/chem/species.d.mts +47 -0
- package/dist/chem/species.mjs +128 -0
- package/dist/chem/stereo.d.mts +108 -0
- package/dist/chem/stereo.mjs +286 -0
- package/dist/chem/stoichiometry.d.mts +95 -0
- package/dist/chem/stoichiometry.mjs +145 -0
- package/dist/chem/synthesis.d.mts +113 -0
- package/dist/chem/synthesis.mjs +281 -0
- package/dist/chem/vsepr.d.mts +80 -0
- package/dist/chem/vsepr.mjs +247 -0
- package/dist/circuit/ac.d.mts +163 -0
- package/dist/circuit/ac.mjs +452 -0
- package/dist/circuit/dc.d.mts +92 -0
- package/dist/circuit/dc.mjs +333 -0
- package/dist/circuit/index.d.mts +5 -92
- package/dist/circuit/index.mjs +5 -332
- package/dist/circuit/network.d.mts +99 -0
- package/dist/circuit/network.mjs +440 -0
- package/dist/circuit/topology.d.mts +102 -0
- package/dist/circuit/topology.mjs +143 -0
- package/dist/colour/absorption.d.mts +79 -0
- package/dist/colour/absorption.mjs +137 -0
- package/dist/colour/index.d.mts +6 -0
- package/dist/colour/index.mjs +7 -0
- package/dist/colour/name.d.mts +14 -0
- package/dist/colour/name.mjs +76 -0
- package/dist/colour/observer.d.mts +31 -0
- package/dist/colour/observer.mjs +46 -0
- package/dist/colour/spectrum.d.mts +61 -0
- package/dist/colour/spectrum.mjs +108 -0
- package/dist/colour/srgb.d.mts +49 -0
- package/dist/colour/srgb.mjs +108 -0
- package/dist/core/constants.d.mts +138 -0
- package/dist/core/constants.mjs +139 -0
- package/dist/core/index.d.mts +4 -1
- package/dist/core/index.mjs +4 -1
- package/dist/core/math.d.mts +26 -0
- package/dist/core/math.mjs +37 -0
- package/dist/core/vec3.d.mts +94 -0
- package/dist/core/vec3.mjs +123 -0
- package/dist/core/worked.d.mts +35 -0
- package/dist/core/worked.mjs +44 -0
- package/dist/electro/cell.d.mts +102 -0
- package/dist/electro/cell.mjs +170 -0
- package/dist/electro/conductivity.d.mts +157 -0
- package/dist/electro/conductivity.mjs +156 -0
- package/dist/electro/couples.d.mts +114 -0
- package/dist/electro/couples.mjs +334 -0
- package/dist/electro/electrolysis.d.mts +96 -0
- package/dist/electro/electrolysis.mjs +274 -0
- package/dist/electro/faraday.d.mts +150 -0
- package/dist/electro/faraday.mjs +118 -0
- package/dist/electro/index.d.mts +6 -0
- package/dist/electro/index.mjs +7 -0
- package/dist/finance/accounting/adjustments.d.mts +17 -0
- package/dist/finance/accounting/adjustments.mjs +202 -0
- package/dist/finance/accounting/analysis.d.mts +8 -0
- package/dist/finance/accounting/analysis.mjs +205 -0
- package/dist/finance/accounting/clubs.d.mts +21 -0
- package/dist/finance/accounting/clubs.mjs +217 -0
- package/dist/finance/accounting/company-statements.d.mts +7 -0
- package/dist/finance/accounting/company-statements.mjs +150 -0
- package/dist/finance/accounting/harness.d.mts +7 -0
- package/dist/finance/accounting/harness.mjs +45 -0
- package/dist/finance/accounting/index.d.mts +18 -0
- package/dist/finance/accounting/index.mjs +18 -0
- package/dist/finance/accounting/journalize.d.mts +16 -0
- package/dist/finance/accounting/journalize.mjs +128 -0
- package/dist/finance/accounting/manufacturing.d.mts +8 -0
- package/dist/finance/accounting/manufacturing.mjs +236 -0
- package/dist/finance/accounting/partnership.d.mts +7 -0
- package/dist/finance/accounting/partnership.mjs +152 -0
- package/dist/finance/accounting/period-case.d.mts +6 -0
- package/dist/finance/accounting/period-case.mjs +71 -0
- package/dist/finance/accounting/post.d.mts +9 -0
- package/dist/finance/accounting/post.mjs +84 -0
- package/dist/finance/accounting/precision.d.mts +9 -0
- package/dist/finance/accounting/precision.mjs +15 -0
- package/dist/finance/accounting/rules.d.mts +21 -0
- package/dist/finance/accounting/rules.mjs +37 -0
- package/dist/finance/accounting/solve.d.mts +28 -0
- package/dist/finance/accounting/solve.mjs +92 -0
- package/dist/finance/accounting/statements.d.mts +7 -0
- package/dist/finance/accounting/statements.mjs +142 -0
- package/dist/finance/accounting/types.d.mts +649 -0
- package/dist/finance/accounting/validate.d.mts +7 -0
- package/dist/finance/accounting/validate.mjs +67 -0
- package/dist/finance/accounting/verification.d.mts +24 -0
- package/dist/finance/accounting/verification.mjs +386 -0
- package/dist/finance/bizsim.d.mts +75 -0
- package/dist/finance/bizsim.mjs +296 -0
- package/dist/finance/index.d.mts +95 -0
- package/dist/finance/index.mjs +145 -0
- package/dist/finance/investment-math.d.mts +7 -0
- package/dist/finance/investment-math.mjs +18 -0
- package/dist/finance/management-accounting/budgeting.d.mts +7 -0
- package/dist/finance/management-accounting/budgeting.mjs +189 -0
- package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
- package/dist/finance/management-accounting/cash-budget.mjs +154 -0
- package/dist/finance/management-accounting/costing.d.mts +8 -0
- package/dist/finance/management-accounting/costing.mjs +175 -0
- package/dist/finance/management-accounting/decisions.d.mts +8 -0
- package/dist/finance/management-accounting/decisions.mjs +164 -0
- package/dist/finance/management-accounting/index.d.mts +13 -0
- package/dist/finance/management-accounting/index.mjs +13 -0
- package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
- package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
- package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
- package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
- package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
- package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
- package/dist/finance/management-accounting/management-case.d.mts +8 -0
- package/dist/finance/management-accounting/management-case.mjs +91 -0
- package/dist/finance/management-accounting/master-budget.d.mts +7 -0
- package/dist/finance/management-accounting/master-budget.mjs +137 -0
- package/dist/finance/management-accounting/production-costing.d.mts +8 -0
- package/dist/finance/management-accounting/production-costing.mjs +214 -0
- package/dist/finance/management-accounting/types.d.mts +644 -0
- package/dist/finance/management-accounting/variances.d.mts +7 -0
- package/dist/finance/management-accounting/variances.mjs +150 -0
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +5 -5
- package/dist/interaction/MovableDot.mjs +19 -0
- package/dist/interaction/useDraggable.mjs +24 -4
- package/dist/math/analysis.d.mts +61 -0
- package/dist/math/analysis.mjs +187 -0
- package/dist/math/answer-check.d.mts +50 -0
- package/dist/math/answer-check.mjs +106 -0
- package/dist/math/calculus.d.mts +17 -1
- package/dist/math/calculus.mjs +365 -2
- package/dist/math/complex.d.mts +93 -0
- package/dist/math/complex.mjs +239 -0
- package/dist/math/expr.d.mts +23 -0
- package/dist/math/expr.mjs +36 -0
- package/dist/math/index.d.mts +9 -23
- package/dist/math/index.mjs +9 -38
- package/dist/math/latex.mjs +10 -1
- package/dist/math/parse.mjs +1 -1
- package/dist/math/poly.d.mts +55 -0
- package/dist/math/poly.mjs +273 -0
- package/dist/math/rearrange.d.mts +14 -0
- package/dist/math/rearrange.mjs +125 -0
- package/dist/math/solve.d.mts +21 -0
- package/dist/math/solve.mjs +75 -0
- package/dist/networking/addressing.d.mts +26 -0
- package/dist/networking/addressing.mjs +33 -0
- package/dist/networking/cloud/access.d.mts +36 -0
- package/dist/networking/cloud/access.mjs +95 -0
- package/dist/networking/cloud/containers.d.mts +43 -0
- package/dist/networking/cloud/containers.mjs +54 -0
- package/dist/networking/cloud/edge.d.mts +17 -0
- package/dist/networking/cloud/edge.mjs +31 -0
- package/dist/networking/cloud/failure-domains.d.mts +19 -0
- package/dist/networking/cloud/failure-domains.mjs +22 -0
- package/dist/networking/cloud/geo-routing.d.mts +22 -0
- package/dist/networking/cloud/geo-routing.mjs +64 -0
- package/dist/networking/cloud/index.d.mts +18 -0
- package/dist/networking/cloud/index.mjs +19 -0
- package/dist/networking/cloud/inference-reliability.d.mts +30 -0
- package/dist/networking/cloud/inference-reliability.mjs +76 -0
- package/dist/networking/cloud/inference.d.mts +118 -0
- package/dist/networking/cloud/inference.mjs +179 -0
- package/dist/networking/cloud/infrastructure.d.mts +45 -0
- package/dist/networking/cloud/infrastructure.mjs +96 -0
- package/dist/networking/cloud/observability.d.mts +24 -0
- package/dist/networking/cloud/observability.mjs +34 -0
- package/dist/networking/cloud/orchestration.d.mts +32 -0
- package/dist/networking/cloud/orchestration.mjs +38 -0
- package/dist/networking/cloud/recovery.d.mts +21 -0
- package/dist/networking/cloud/recovery.mjs +27 -0
- package/dist/networking/cloud/releases.d.mts +42 -0
- package/dist/networking/cloud/releases.mjs +135 -0
- package/dist/networking/cloud/scaling.d.mts +25 -0
- package/dist/networking/cloud/scaling.mjs +65 -0
- package/dist/networking/cloud/secrets.d.mts +39 -0
- package/dist/networking/cloud/secrets.mjs +68 -0
- package/dist/networking/cloud/server-deployment.d.mts +29 -0
- package/dist/networking/cloud/server-deployment.mjs +72 -0
- package/dist/networking/cloud/storage.d.mts +16 -0
- package/dist/networking/cloud/storage.mjs +58 -0
- package/dist/networking/cloud/vpc.d.mts +18 -0
- package/dist/networking/cloud/vpc.mjs +100 -0
- package/dist/networking/delivery.d.mts +34 -0
- package/dist/networking/delivery.mjs +52 -0
- package/dist/networking/index.d.mts +47 -0
- package/dist/networking/index.mjs +47 -0
- package/dist/networking/ipv6.d.mts +28 -0
- package/dist/networking/ipv6.mjs +17 -0
- package/dist/networking/journeys.d.mts +83 -0
- package/dist/networking/journeys.mjs +161 -0
- package/dist/networking/models/airtime.d.mts +87 -0
- package/dist/networking/models/airtime.mjs +130 -0
- package/dist/networking/models/cellular.d.mts +157 -0
- package/dist/networking/models/cellular.mjs +252 -0
- package/dist/networking/models/encapsulation.d.mts +98 -0
- package/dist/networking/models/encapsulation.mjs +132 -0
- package/dist/networking/models/handover.d.mts +116 -0
- package/dist/networking/models/handover.mjs +209 -0
- package/dist/networking/models/handshake.d.mts +90 -0
- package/dist/networking/models/handshake.mjs +122 -0
- package/dist/networking/models/index.d.mts +14 -0
- package/dist/networking/models/index.mjs +15 -0
- package/dist/networking/models/media.d.mts +82 -0
- package/dist/networking/models/media.mjs +188 -0
- package/dist/networking/models/satellite.d.mts +86 -0
- package/dist/networking/models/satellite.mjs +121 -0
- package/dist/networking/models/spectrum.d.mts +83 -0
- package/dist/networking/models/spectrum.mjs +235 -0
- package/dist/networking/models/switch.d.mts +80 -0
- package/dist/networking/models/switch.mjs +155 -0
- package/dist/networking/models/vlan.d.mts +62 -0
- package/dist/networking/models/vlan.mjs +100 -0
- package/dist/networking/models/vpn.d.mts +66 -0
- package/dist/networking/models/vpn.mjs +125 -0
- package/dist/networking/models/wifi-privacy.d.mts +82 -0
- package/dist/networking/models/wifi-privacy.mjs +130 -0
- package/dist/networking/models/wifi.d.mts +240 -0
- package/dist/networking/models/wifi.mjs +562 -0
- package/dist/networking/nat-traversal.d.mts +24 -0
- package/dist/networking/nat-traversal.mjs +38 -0
- package/dist/networking/protocols.d.mts +17 -0
- package/dist/networking/protocols.mjs +57 -0
- package/dist/networking/queue.d.mts +12 -0
- package/dist/networking/queue.mjs +18 -0
- package/dist/networking/route-learning.d.mts +23 -0
- package/dist/networking/route-learning.mjs +43 -0
- package/dist/networking/routing.d.mts +11 -0
- package/dist/networking/routing.mjs +25 -0
- package/dist/networking/signals.d.mts +26 -0
- package/dist/networking/signals.mjs +35 -0
- package/dist/networking/subnet.d.mts +49 -0
- package/dist/networking/subnet.mjs +89 -0
- package/dist/networking/tcp-reliability.d.mts +24 -0
- package/dist/networking/tcp-reliability.mjs +38 -0
- package/dist/networking/topology/contract.d.mts +123 -0
- package/dist/networking/topology/index.d.mts +4 -0
- package/dist/networking/topology/index.mjs +4 -0
- package/dist/networking/topology/presets.d.mts +7 -0
- package/dist/networking/topology/presets.mjs +302 -0
- package/dist/networking/topology/simulation.d.mts +8 -0
- package/dist/networking/topology/simulation.mjs +179 -0
- package/dist/networking/wireless.d.mts +11 -0
- package/dist/networking/wireless.mjs +17 -0
- package/dist/optics/imaging.d.mts +218 -0
- package/dist/optics/imaging.mjs +276 -0
- package/dist/optics/index.d.mts +7 -0
- package/dist/optics/index.mjs +8 -0
- package/dist/optics/laws.d.mts +70 -0
- package/dist/optics/laws.mjs +195 -0
- package/dist/optics/prism.d.mts +148 -0
- package/dist/optics/prism.mjs +197 -0
- package/dist/optics/refraction.d.mts +201 -0
- package/dist/optics/refraction.mjs +270 -0
- package/dist/optics/wave-optics.d.mts +171 -0
- package/dist/optics/wave-optics.mjs +259 -0
- package/dist/physics/ac/index.d.mts +183 -0
- package/dist/physics/ac/index.mjs +203 -0
- package/dist/physics/dynamics/forces.d.mts +98 -0
- package/dist/physics/dynamics/forces.mjs +153 -0
- package/dist/physics/dynamics/friction.d.mts +76 -0
- package/dist/physics/dynamics/friction.mjs +119 -0
- package/dist/physics/dynamics/system.d.mts +68 -0
- package/dist/physics/dynamics/system.mjs +125 -0
- package/dist/physics/electrostatics/index.d.mts +169 -0
- package/dist/physics/electrostatics/index.mjs +249 -0
- package/dist/physics/energy/centre-of-mass.d.mts +115 -0
- package/dist/physics/energy/centre-of-mass.mjs +180 -0
- package/dist/physics/energy/conservation.d.mts +81 -0
- package/dist/physics/energy/conservation.mjs +129 -0
- package/dist/physics/energy/power.d.mts +90 -0
- package/dist/physics/energy/power.mjs +167 -0
- package/dist/physics/energy/spring.d.mts +73 -0
- package/dist/physics/energy/spring.mjs +129 -0
- package/dist/physics/energy/store.d.mts +63 -0
- package/dist/physics/energy/store.mjs +108 -0
- package/dist/physics/energy/theorem.d.mts +65 -0
- package/dist/physics/energy/theorem.mjs +113 -0
- package/dist/physics/energy/work.d.mts +114 -0
- package/dist/physics/energy/work.mjs +219 -0
- package/dist/physics/gravitation/body.d.mts +85 -0
- package/dist/physics/gravitation/body.mjs +168 -0
- package/dist/physics/gravitation/kepler.d.mts +127 -0
- package/dist/physics/gravitation/kepler.mjs +216 -0
- package/dist/physics/gravitation/law.d.mts +117 -0
- package/dist/physics/gravitation/law.mjs +175 -0
- package/dist/physics/gravitation/orbit.d.mts +119 -0
- package/dist/physics/gravitation/orbit.mjs +202 -0
- package/dist/physics/gravitation/potential.d.mts +114 -0
- package/dist/physics/gravitation/potential.mjs +202 -0
- package/dist/physics/gravitation/variation.d.mts +97 -0
- package/dist/physics/gravitation/variation.mjs +175 -0
- package/dist/physics/index.d.mts +35 -0
- package/dist/physics/index.mjs +36 -0
- package/dist/physics/integral-sweep.d.mts +63 -0
- package/dist/physics/integral-sweep.mjs +126 -0
- package/dist/physics/kinematics/equations.d.mts +47 -0
- package/dist/physics/kinematics/equations.mjs +126 -0
- package/dist/physics/kinematics/free-fall.d.mts +53 -0
- package/dist/physics/kinematics/free-fall.mjs +71 -0
- package/dist/physics/kinematics/given.d.mts +16 -0
- package/dist/physics/kinematics/given.mjs +55 -0
- package/dist/physics/kinematics/roots.d.mts +41 -0
- package/dist/physics/kinematics/roots.mjs +72 -0
- package/dist/physics/kinematics/solve.d.mts +52 -0
- package/dist/physics/kinematics/solve.mjs +172 -0
- package/dist/physics/magnetism/biot-savart.d.mts +161 -0
- package/dist/physics/magnetism/biot-savart.mjs +353 -0
- package/dist/physics/magnetism/flux.d.mts +94 -0
- package/dist/physics/magnetism/flux.mjs +313 -0
- package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
- package/dist/physics/magnetism/geomagnetism.mjs +184 -0
- package/dist/physics/magnetism/index.d.mts +12 -0
- package/dist/physics/magnetism/index.mjs +74 -0
- package/dist/physics/magnetism/lorentz.d.mts +28 -0
- package/dist/physics/magnetism/lorentz.mjs +88 -0
- package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
- package/dist/physics/magnetism/magnetic-force.mjs +169 -0
- package/dist/physics/momentum/collide.d.mts +77 -0
- package/dist/physics/momentum/collide.mjs +115 -0
- package/dist/physics/momentum/impulse.d.mts +89 -0
- package/dist/physics/momentum/impulse.mjs +159 -0
- package/dist/physics/momentum/planar.d.mts +60 -0
- package/dist/physics/momentum/planar.mjs +110 -0
- package/dist/physics/projectile.d.mts +107 -0
- package/dist/physics/projectile.mjs +185 -0
- package/dist/physics/rotation/angular.d.mts +85 -0
- package/dist/physics/rotation/angular.mjs +130 -0
- package/dist/physics/rotation/circular.d.mts +79 -0
- package/dist/physics/rotation/circular.mjs +131 -0
- package/dist/physics/rotation/inertia.d.mts +164 -0
- package/dist/physics/rotation/inertia.mjs +332 -0
- package/dist/physics/rotation/torque.d.mts +65 -0
- package/dist/physics/rotation/torque.mjs +134 -0
- package/dist/physics/vectors.d.mts +64 -0
- package/dist/physics/vectors.mjs +114 -0
- package/dist/primitives/Dot.d.mts +2 -15
- package/dist/primitives/Dot.mjs +6 -4
- package/dist/primitives/Grid.d.mts +33 -17
- package/dist/primitives/Grid.mjs +89 -17
- package/dist/primitives/Label.d.mts +1 -14
- package/dist/primitives/Label.mjs +3 -2
- package/dist/primitives/Lines.d.mts +4 -32
- package/dist/primitives/Lines.mjs +10 -8
- package/dist/primitives/Shapes.d.mts +5 -43
- package/dist/primitives/Shapes.mjs +12 -10
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/primitives/props.mjs +31 -0
- package/dist/quantity/index.d.mts +119 -0
- package/dist/quantity/index.mjs +417 -0
- package/dist/relation/derive.d.mts +74 -0
- package/dist/relation/derive.mjs +73 -0
- package/dist/relation/index.d.mts +56 -0
- package/dist/relation/index.mjs +234 -0
- package/dist/scene/Scene.d.mts +6 -1
- package/dist/scene/Scene.mjs +15 -40
- package/dist/scene/evaluators.mjs +1 -1
- package/dist/sim/thermal.mjs +45 -20
- package/dist/thermo/calorimetry.d.mts +207 -0
- package/dist/thermo/calorimetry.mjs +345 -0
- package/dist/thermo/cycles.d.mts +142 -0
- package/dist/thermo/cycles.mjs +256 -0
- package/dist/thermo/entropy.d.mts +87 -0
- package/dist/thermo/entropy.mjs +140 -0
- package/dist/thermo/expansion.d.mts +130 -0
- package/dist/thermo/expansion.mjs +178 -0
- package/dist/thermo/gas.d.mts +197 -0
- package/dist/thermo/gas.mjs +279 -0
- package/dist/thermo/heat-transfer.d.mts +164 -0
- package/dist/thermo/heat-transfer.mjs +217 -0
- package/dist/thermo/index.d.mts +9 -82
- package/dist/thermo/index.mjs +9 -132
- package/dist/thermo/processes.d.mts +95 -0
- package/dist/thermo/processes.mjs +154 -0
- package/dist/thermo/temperature.d.mts +174 -0
- package/dist/thermo/temperature.mjs +236 -0
- package/dist/view/Stage.mjs +4 -11
- package/dist/waves/damping.d.mts +224 -0
- package/dist/waves/damping.mjs +317 -0
- package/dist/waves/doppler.d.mts +72 -0
- package/dist/waves/doppler.mjs +125 -0
- package/dist/waves/index.d.mts +10 -0
- package/dist/waves/index.mjs +10 -0
- package/dist/waves/pendulum.d.mts +130 -0
- package/dist/waves/pendulum.mjs +211 -0
- package/dist/waves/pitch.d.mts +125 -0
- package/dist/waves/pitch.mjs +158 -0
- package/dist/waves/shm.d.mts +170 -0
- package/dist/waves/shm.mjs +279 -0
- package/dist/waves/springs.d.mts +103 -0
- package/dist/waves/springs.mjs +176 -0
- package/dist/waves/superposition.d.mts +124 -0
- package/dist/waves/superposition.mjs +196 -0
- package/dist/waves/wave.d.mts +154 -0
- package/dist/waves/wave.mjs +178 -0
- package/package.json +103 -23
- package/styles.css +125 -8
- package/dist/assets/kit/index.mjs +0 -4
|
@@ -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 };
|
package/dist/math/calculus.d.mts
CHANGED
|
@@ -3,7 +3,23 @@ import { Node } from "./ast.mjs";
|
|
|
3
3
|
//#region src/math/calculus.d.ts
|
|
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
|
+
/**
|
|
7
|
+
* Exact symbolic antiderivative, trying the expression as written and then multiplied out.
|
|
8
|
+
*
|
|
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.
|
|
12
|
+
*/
|
|
13
|
+
declare function integrate(node: Node, x: string): Node | null;
|
|
14
|
+
/**
|
|
15
|
+
* A definite integral evaluated exactly: `F(b) - F(a)`.
|
|
16
|
+
*
|
|
17
|
+
* Returned as a NUMBER rather than a node, because that is what a lesson compares a learner's
|
|
18
|
+
* answer against. Null when the antiderivative is not elementary, or when either limit lands
|
|
19
|
+
* somewhere the expression is not defined.
|
|
20
|
+
*/
|
|
21
|
+
declare function definiteIntegral(node: Node, x: string, lower: number, upper: number): number | null;
|
|
6
22
|
/** Fold constants and trivial identities so derivative output is readable. */
|
|
7
23
|
declare function simplify(node: Node): Node;
|
|
8
24
|
//#endregion
|
|
9
|
-
export { differentiate, simplify };
|
|
25
|
+
export { definiteIntegral, differentiate, integrate, simplify };
|
package/dist/math/calculus.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FN1, FN2 } from "./defs.mjs";
|
|
2
|
-
import { add, call, div, mul, neg, num, pow, sub } from "./ast.mjs";
|
|
2
|
+
import { add, call, div, evaluate, mul, neg, num, pow, sub, variable } from "./ast.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/math/calculus.ts
|
|
5
5
|
/**
|
|
@@ -70,6 +70,343 @@ function differentiate(node, x) {
|
|
|
70
70
|
default: return null;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Outer antiderivative of a 1-arg function, given its argument node `u`.
|
|
75
|
+
*
|
|
76
|
+
* Mirrors DERIV above. Only the functions whose antiderivative is itself elementary appear:
|
|
77
|
+
* `ln` and the inverse trig functions integrate by parts into forms this table cannot express,
|
|
78
|
+
* so they are absent and `integrate` returns null for them rather than guessing.
|
|
79
|
+
*/
|
|
80
|
+
const INTEG = {
|
|
81
|
+
sin: (u) => neg(call("cos", u)),
|
|
82
|
+
cos: (u) => call("sin", u),
|
|
83
|
+
exp: (u) => call("exp", u),
|
|
84
|
+
sinh: (u) => call("cosh", u),
|
|
85
|
+
cosh: (u) => call("sinh", u)
|
|
86
|
+
};
|
|
87
|
+
/** `true` when `node` holds no occurrence of `x`, so it is a constant for this integral. */
|
|
88
|
+
function isConstantIn(node, x) {
|
|
89
|
+
return !freeVarsHas(node, x);
|
|
90
|
+
}
|
|
91
|
+
function freeVarsHas(node, x) {
|
|
92
|
+
switch (node.type) {
|
|
93
|
+
case "num": return false;
|
|
94
|
+
case "var": return node.name === x;
|
|
95
|
+
case "neg": return freeVarsHas(node.arg, x);
|
|
96
|
+
case "binary": return freeVarsHas(node.left, x) || freeVarsHas(node.right, x);
|
|
97
|
+
case "call": return node.args.some((a) => freeVarsHas(a, x));
|
|
98
|
+
default: return true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The constant `a` when `u` is linear in `x` (that is, `u = a·x + b`), else null.
|
|
103
|
+
*
|
|
104
|
+
* This is what makes the whole linear-substitution family work with one rule instead of a pattern
|
|
105
|
+
* per case: if `du/dx` simplifies to a non-zero NUMBER, then `∫f(u) dx = F(u)/a`. Deriving it from
|
|
106
|
+
* `differentiate` rather than matching `a*x+b` by shape means `(3-2x)^5` and `(-2x+3)^5` and
|
|
107
|
+
* `3-2*x` all work without three separate matchers.
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* The `a` in `u = ax + b`, as a NODE, or null when `u` is not linear in `x`.
|
|
111
|
+
*
|
|
112
|
+
* It used to demand a numeric `a`, which made `sin(2x)` integrable and `sin(ωt)` not. That is the
|
|
113
|
+
* wrong line to draw for physics: a coefficient that is a symbol is still a constant with respect
|
|
114
|
+
* to the integration variable, and `exp(-λt)`, `sin(ωt)` and `cos(kx)` are the shape of half the
|
|
115
|
+
* integrals in waves, decay and alternating current. The test is "does d/dx vanish under further
|
|
116
|
+
* differentiation", not "is it a literal number".
|
|
117
|
+
*/
|
|
118
|
+
function linearFactor(u, x) {
|
|
119
|
+
const d = differentiate(u, x);
|
|
120
|
+
if (!d) return null;
|
|
121
|
+
const s = simplify(d);
|
|
122
|
+
if (freeVarsHas(s, x)) return null;
|
|
123
|
+
if (s.type === "num" && s.value === 0) return null;
|
|
124
|
+
return s;
|
|
125
|
+
}
|
|
126
|
+
/** Divide by the linear coefficient, without emitting the noise of `expr / 1`. */
|
|
127
|
+
const overConst = (node, a) => a.type === "num" && a.value === 1 ? node : div(node, a);
|
|
128
|
+
/**
|
|
129
|
+
* Exact symbolic antiderivative with respect to `x`, or `null` when this engine cannot do it.
|
|
130
|
+
*
|
|
131
|
+
* The constant of integration is NOT included. That is deliberate: `+ c` is the single most
|
|
132
|
+
* commonly dropped mark in the topic, so it belongs in the lesson's own working where a learner
|
|
133
|
+
* has to write it, not silently bolted on by the engine.
|
|
134
|
+
*
|
|
135
|
+
* Covers: linearity, the power rule including the `1/x → ln|x|` exception, any of those composed
|
|
136
|
+
* with a linear inner function whose coefficient may be a SYMBOL (`sin(ωt)`, `e^{-λt}`), and any
|
|
137
|
+
* polynomial that becomes one of the above after being multiplied out.
|
|
138
|
+
*
|
|
139
|
+
* Returns null for integration by parts (`x·eˣ`), non-linear substitution (`√(1−x²)`, `x/(1+x²)`)
|
|
140
|
+
* and trigonometric powers (`sin²x`). A caller that must produce a number regardless should fall
|
|
141
|
+
* back to `quadrature` in `analysis.ts` and say that it did, rather than show a wrong formula.
|
|
142
|
+
* `physics/integral-sweep` is the worked example of that pattern.
|
|
143
|
+
*/
|
|
144
|
+
/**
|
|
145
|
+
* Squares and cubes of the trigonometric functions.
|
|
146
|
+
*
|
|
147
|
+
* These are not power-rule cases and they are not substitutions either. Each is a standard identity
|
|
148
|
+
* that turns the power into something already integrable:
|
|
149
|
+
*
|
|
150
|
+
* ∫sin²u du = u/2 − sin 2u / 4 the double-angle identity, cos 2u = 1 − 2sin²u
|
|
151
|
+
* ∫cos²u du = u/2 + sin 2u / 4
|
|
152
|
+
* ∫sin³u du = −cos u + cos³u / 3 writing sin³ as sin·(1 − cos²) and substituting
|
|
153
|
+
* ∫cos³u du = sin u − sin³u / 3
|
|
154
|
+
* ∫tan²u du = tan u − u from sec² = 1 + tan²
|
|
155
|
+
*
|
|
156
|
+
* WHY THESE FIVE AND NOT A GENERAL REDUCTION FORMULA. Squares are the ones that actually turn up:
|
|
157
|
+
* mean power in an alternating circuit is `∫sin²`, a spherical shell parameterised by angle is
|
|
158
|
+
* `∫sin³`, and between them they cover the syllabus. A general `sin^n` reduction is a much larger
|
|
159
|
+
* commitment for cases nobody sets, and returning null for `sin⁴` is honest.
|
|
160
|
+
*
|
|
161
|
+
* The inner function may be linear with a symbolic coefficient, so `sin²(ωt)` works, which is the
|
|
162
|
+
* form every alternating-current question is actually written in.
|
|
163
|
+
*/
|
|
164
|
+
function integrateTrigPower(base, n, x) {
|
|
165
|
+
if (base.type !== "call" || base.args.length !== 1) return null;
|
|
166
|
+
const u = base.args[0];
|
|
167
|
+
if (!u) return null;
|
|
168
|
+
const a = linearFactor(u, x);
|
|
169
|
+
if (a === null) return null;
|
|
170
|
+
const sin = (arg) => call("sin", arg);
|
|
171
|
+
const cos = (arg) => call("cos", arg);
|
|
172
|
+
if (n === 2) {
|
|
173
|
+
if (base.fn === "sin") return overConst(sub(div(u, num(2)), div(sin(mul(num(2), u)), num(4))), a);
|
|
174
|
+
if (base.fn === "cos") return overConst(add(div(u, num(2)), div(sin(mul(num(2), u)), num(4))), a);
|
|
175
|
+
if (base.fn === "tan") return overConst(sub(call("tan", u), u), a);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
if (n === 3) {
|
|
179
|
+
if (base.fn === "sin") return overConst(add(neg(cos(u)), div(pow(cos(u), num(3)), num(3))), a);
|
|
180
|
+
if (base.fn === "cos") return overConst(sub(sin(u), div(pow(sin(u), num(3)), num(3))), a);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
/** How far `expand` will raise a sum before giving up. 8 covers anything at this level. */
|
|
186
|
+
const MAX_EXPAND_POWER = 8;
|
|
187
|
+
/**
|
|
188
|
+
* Multiply out products and integer powers of sums: `(R² − x²)²` becomes `R⁴ − 2R²x² + x⁴`.
|
|
189
|
+
*
|
|
190
|
+
* This exists because of a sharp edge in the integrator. It handles a sum term by term and a power
|
|
191
|
+
* of a LINEAR inner function, so `R⁴ − 2R²x² + x⁴` integrates and the identical `(R² − x²)²` does
|
|
192
|
+
* not. A student writing the moment of inertia of a sphere writes the second form, and being told
|
|
193
|
+
* it is not integrable while its expansion is would be indefensible.
|
|
194
|
+
*
|
|
195
|
+
* Not a general simplifier and not a normal form: it distributes and it raises, and it leaves
|
|
196
|
+
* everything else alone. `simplify` is still what tidies the result.
|
|
197
|
+
*/
|
|
198
|
+
function expand(node) {
|
|
199
|
+
switch (node.type) {
|
|
200
|
+
case "neg": return neg(expand(node.arg));
|
|
201
|
+
case "call": return call(node.fn, ...node.args.map(expand));
|
|
202
|
+
case "binary": {
|
|
203
|
+
const left = expand(node.left);
|
|
204
|
+
const right = expand(node.right);
|
|
205
|
+
switch (node.op) {
|
|
206
|
+
case "+": return add(left, right);
|
|
207
|
+
case "-": return sub(left, right);
|
|
208
|
+
case "*": return distribute(left, right);
|
|
209
|
+
case "/": return isSum(left) ? expand(distributeOverSum(left, (t) => div(t, right))) : div(left, right);
|
|
210
|
+
case "^": {
|
|
211
|
+
const exponent = simplify(right);
|
|
212
|
+
if (!isSum(left) || exponent.type !== "num") return pow(left, right);
|
|
213
|
+
const n = exponent.value;
|
|
214
|
+
if (!Number.isInteger(n) || n < 2 || n > MAX_EXPAND_POWER) return pow(left, right);
|
|
215
|
+
let out = left;
|
|
216
|
+
for (let i = 1; i < n; i++) out = distribute(out, left);
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
default: return {
|
|
220
|
+
...node,
|
|
221
|
+
left,
|
|
222
|
+
right
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
default: return node;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const isSum = (node) => node.type === "binary" && (node.op === "+" || node.op === "-");
|
|
230
|
+
/** Apply `f` to each term of a sum, preserving the signs. */
|
|
231
|
+
function distributeOverSum(sum, f) {
|
|
232
|
+
if (sum.type === "binary" && sum.op === "+") return add(distributeOverSum(sum.left, f), distributeOverSum(sum.right, f));
|
|
233
|
+
if (sum.type === "binary" && sum.op === "-") return sub(distributeOverSum(sum.left, f), distributeOverSum(sum.right, f));
|
|
234
|
+
return f(sum);
|
|
235
|
+
}
|
|
236
|
+
/** `(a + b)(c + d)` term by term, in whichever direction has a sum. */
|
|
237
|
+
function distribute(left, right) {
|
|
238
|
+
if (isSum(left)) return distributeOverSum(left, (term) => distribute(term, right));
|
|
239
|
+
if (isSum(right)) return distributeOverSum(right, (term) => distribute(left, term));
|
|
240
|
+
return mul(left, right);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* A structural key for a node, so two occurrences of the same factor can be recognised.
|
|
244
|
+
*
|
|
245
|
+
* Deliberately crude and deliberately not a canonical form: `x*y` and `y*x` get different keys, so
|
|
246
|
+
* they are not merged. Merging them would need an ordering over expressions, which is a much larger
|
|
247
|
+
* commitment than this needs. Failing to merge costs nothing except a missed simplification.
|
|
248
|
+
*/
|
|
249
|
+
function key(node) {
|
|
250
|
+
switch (node.type) {
|
|
251
|
+
case "num": return `#${node.value}`;
|
|
252
|
+
case "var": return `$${node.name}`;
|
|
253
|
+
case "neg": return `-(${key(node.arg)})`;
|
|
254
|
+
case "binary": return `(${key(node.left)}${node.op}${key(node.right)})`;
|
|
255
|
+
case "call": return `${node.fn}(${node.args.map(key).join(",")})`;
|
|
256
|
+
default: return "?";
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Gather repeated factors into powers: `x·x` becomes `x²`, and `(x+1)/x` becomes `1 + x⁻¹`.
|
|
261
|
+
*
|
|
262
|
+
* Without this, `expand` is almost useless to the integrator. `∫x(x+1)dx` expands to `∫(x·x + x)dx`
|
|
263
|
+
* and the power rule reads `^`, not repeated multiplication, so it would still refuse. Division is
|
|
264
|
+
* folded in as a negative exponent, which is also what lets the `1/x → ln|x|` rule be reached
|
|
265
|
+
* through a quotient that was written as a fraction of sums.
|
|
266
|
+
*/
|
|
267
|
+
function collect(node) {
|
|
268
|
+
const factors = [];
|
|
269
|
+
let numeric = 1;
|
|
270
|
+
let ok = true;
|
|
271
|
+
const gather = (n, sign) => {
|
|
272
|
+
if (!ok) return;
|
|
273
|
+
if (n.type === "binary" && n.op === "*") {
|
|
274
|
+
gather(n.left, sign);
|
|
275
|
+
gather(n.right, sign);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (n.type === "binary" && n.op === "/") {
|
|
279
|
+
gather(n.left, sign);
|
|
280
|
+
gather(n.right, sign === 1 ? -1 : 1);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
let base = n;
|
|
284
|
+
let exponent = 1;
|
|
285
|
+
if (n.type === "binary" && n.op === "^") {
|
|
286
|
+
const e = simplify(n.right);
|
|
287
|
+
if (e.type === "num" && Number.isFinite(e.value)) {
|
|
288
|
+
base = n.left;
|
|
289
|
+
exponent = e.value;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (base.type === "num") {
|
|
293
|
+
if (exponent !== 1 && !Number.isInteger(exponent)) ok = false;
|
|
294
|
+
numeric *= Math.pow(base.value, sign * exponent);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const k = key(base);
|
|
298
|
+
const found = factors.find((f) => key(f.base) === k);
|
|
299
|
+
if (found) found.exponent += sign * exponent;
|
|
300
|
+
else factors.push({
|
|
301
|
+
base,
|
|
302
|
+
exponent: sign * exponent
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
gather(node, 1);
|
|
306
|
+
if (!ok) return node;
|
|
307
|
+
const parts = [];
|
|
308
|
+
for (const { base, exponent } of factors) {
|
|
309
|
+
if (exponent === 0) continue;
|
|
310
|
+
parts.push(exponent === 1 ? base : pow(base, num(exponent)));
|
|
311
|
+
}
|
|
312
|
+
if (numeric !== 1 || parts.length === 0) parts.unshift(num(numeric));
|
|
313
|
+
return parts.reduce((a, b) => mul(a, b));
|
|
314
|
+
}
|
|
315
|
+
/** Run `collect` over every product in a sum, leaving the sum's shape alone. */
|
|
316
|
+
function collectAll(node) {
|
|
317
|
+
if (node.type === "binary" && (node.op === "+" || node.op === "-")) {
|
|
318
|
+
const left = collectAll(node.left);
|
|
319
|
+
const right = collectAll(node.right);
|
|
320
|
+
return node.op === "+" ? add(left, right) : sub(left, right);
|
|
321
|
+
}
|
|
322
|
+
if (node.type === "neg") return neg(collectAll(node.arg));
|
|
323
|
+
if (node.type === "binary" && (node.op === "*" || node.op === "/")) return collect(node);
|
|
324
|
+
return node;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Exact symbolic antiderivative, trying the expression as written and then multiplied out.
|
|
328
|
+
*
|
|
329
|
+
* The second attempt is what makes `∫x(x+1)dx` and `∫(R²−x²)²dx` work: expand distributes, collect
|
|
330
|
+
* turns the resulting repeated factors back into powers, and then the ordinary power rule applies
|
|
331
|
+
* term by term. A single retry, because both passes are idempotent on their own output.
|
|
332
|
+
*/
|
|
333
|
+
function integrate(node, x) {
|
|
334
|
+
return integrateDirect(node, x) ?? integrateDirect(collectAll(expand(node)), x);
|
|
335
|
+
}
|
|
336
|
+
function integrateDirect(node, x) {
|
|
337
|
+
if (isConstantIn(node, x)) return mul(node, variable(x));
|
|
338
|
+
switch (node.type) {
|
|
339
|
+
case "var": return div(pow(variable(x), num(2)), num(2));
|
|
340
|
+
case "neg": {
|
|
341
|
+
const inner = integrate(node.arg, x);
|
|
342
|
+
return inner && neg(inner);
|
|
343
|
+
}
|
|
344
|
+
case "binary": {
|
|
345
|
+
const { op, left, right } = node;
|
|
346
|
+
if (op === "+" || op === "-") {
|
|
347
|
+
const l = integrate(left, x);
|
|
348
|
+
const r = integrate(right, x);
|
|
349
|
+
return l && r && (op === "+" ? add(l, r) : sub(l, r));
|
|
350
|
+
}
|
|
351
|
+
if (op === "*") {
|
|
352
|
+
if (isConstantIn(left, x)) {
|
|
353
|
+
const r = integrate(right, x);
|
|
354
|
+
return r && mul(left, r);
|
|
355
|
+
}
|
|
356
|
+
if (isConstantIn(right, x)) {
|
|
357
|
+
const l = integrate(left, x);
|
|
358
|
+
return l && mul(right, l);
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
if (op === "/") {
|
|
363
|
+
if (isConstantIn(right, x)) {
|
|
364
|
+
const l = integrate(left, x);
|
|
365
|
+
return l && div(l, right);
|
|
366
|
+
}
|
|
367
|
+
if (isConstantIn(left, x)) {
|
|
368
|
+
const a = linearFactor(right, x);
|
|
369
|
+
return a === null ? null : overConst(mul(left, call("ln", call("abs", right))), a);
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
if (op === "^") {
|
|
374
|
+
const exponent = simplify(right);
|
|
375
|
+
if (exponent.type !== "num") return null;
|
|
376
|
+
const n = exponent.value;
|
|
377
|
+
const trig = integrateTrigPower(left, n, x);
|
|
378
|
+
if (trig) return trig;
|
|
379
|
+
const a = linearFactor(left, x);
|
|
380
|
+
if (a === null) return null;
|
|
381
|
+
if (n === -1) return overConst(call("ln", call("abs", left)), a);
|
|
382
|
+
return overConst(div(pow(left, num(n + 1)), num(n + 1)), a);
|
|
383
|
+
}
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
case "call": {
|
|
387
|
+
const u = node.args[0];
|
|
388
|
+
const rule = INTEG[node.fn];
|
|
389
|
+
if (!rule || !u || node.args.length !== 1) return null;
|
|
390
|
+
const a = linearFactor(u, x);
|
|
391
|
+
return a === null ? null : overConst(rule(u), a);
|
|
392
|
+
}
|
|
393
|
+
default: return null;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* A definite integral evaluated exactly: `F(b) - F(a)`.
|
|
398
|
+
*
|
|
399
|
+
* Returned as a NUMBER rather than a node, because that is what a lesson compares a learner's
|
|
400
|
+
* answer against. Null when the antiderivative is not elementary, or when either limit lands
|
|
401
|
+
* somewhere the expression is not defined.
|
|
402
|
+
*/
|
|
403
|
+
function definiteIntegral(node, x, lower, upper) {
|
|
404
|
+
const F = integrate(node, x);
|
|
405
|
+
if (!F) return null;
|
|
406
|
+
const at = (v) => evaluate(F, { [x]: v });
|
|
407
|
+
const result = at(upper) - at(lower);
|
|
408
|
+
return Number.isFinite(result) ? result : null;
|
|
409
|
+
}
|
|
73
410
|
const isNum = (n, v) => n.type === "num" && (v === void 0 || n.value === v);
|
|
74
411
|
/** A stable structural key, so identical cores group (x and x; x² and x²). */
|
|
75
412
|
function nodeKey(n) {
|
|
@@ -192,10 +529,36 @@ function simplify(node) {
|
|
|
192
529
|
right: l.left
|
|
193
530
|
};
|
|
194
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* Cancel a constant against a fraction's denominator: c·(a/b) → (c/b)·a.
|
|
534
|
+
*
|
|
535
|
+
* `∫3x² dx` is the plainest case. The constant comes out of the integral and the power
|
|
536
|
+
* rule divides by 3, so the honest answer is `3·(x³/3)`. A learner expects `x³`, and
|
|
537
|
+
* only the fully cancelled form is worth showing as the ANSWER.
|
|
538
|
+
*/
|
|
539
|
+
if (l.type === "num" && r.type === "binary" && r.op === "/" && r.right.type === "num") {
|
|
540
|
+
const k = l.value / r.right.value;
|
|
541
|
+
if (Number.isInteger(k)) return k === 1 ? r.left : simplify(mul(num(k), r.left));
|
|
542
|
+
}
|
|
543
|
+
if (r.type === "num" && l.type === "binary" && l.op === "/" && l.right.type === "num") {
|
|
544
|
+
const k = r.value / l.right.value;
|
|
545
|
+
if (Number.isInteger(k)) return k === 1 ? l.left : simplify(mul(num(k), l.left));
|
|
546
|
+
}
|
|
195
547
|
break;
|
|
196
548
|
case "/":
|
|
197
549
|
if (isNum(r, 1)) return l;
|
|
198
550
|
if (isNum(l, 0)) return num(0);
|
|
551
|
+
/**
|
|
552
|
+
* Collapse a nested fraction: (a/b)/c → a/(bc).
|
|
553
|
+
*
|
|
554
|
+
* Integration produces these constantly, because the power rule divides by n+1 and the
|
|
555
|
+
* linear-substitution rule then divides by a. Left alone, ∫(2x+1)³dx renders as a
|
|
556
|
+
* fraction inside a fraction, which is correct and unreadable, and unreadable is the
|
|
557
|
+
* complaint this engine exists to answer.
|
|
558
|
+
*/
|
|
559
|
+
if (r.type === "num" && l.type === "binary" && l.op === "/" && l.right.type === "num") return simplify(div(l.left, num(l.right.value * r.value)));
|
|
560
|
+
if (r.type === "num" && r.value < 0) return simplify(neg(div(l, num(-r.value))));
|
|
561
|
+
if (l.type === "neg") return neg(simplify(div(l.arg, r)));
|
|
199
562
|
break;
|
|
200
563
|
case "^":
|
|
201
564
|
if (isNum(r, 1)) return l;
|
|
@@ -244,4 +607,4 @@ function fold(op, a, b) {
|
|
|
244
607
|
}
|
|
245
608
|
|
|
246
609
|
//#endregion
|
|
247
|
-
export { differentiate, simplify };
|
|
610
|
+
export { definiteIntegral, differentiate, integrate, simplify };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
declare namespace complex_d_exports {
|
|
2
|
+
export { Complex, DEG2RAD, I, MAX_POW, MAX_ROOTS, ONE, RAD2DEG, TWO_PI, ZERO, abs, add, arg, argDeg, conj, cx, div, eq, fromPolar, iPow, isFiniteC, mul, neg, nthRoots, omega, powInt, rootsOfUnity, scale, sub, toPolar, toStr, toTex };
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Complex-number kernel, the pure engine every complex/Argand/polar lab computes
|
|
6
|
+
* against (so a lab — or an agent — never hand-rolls a²+b² or atan2). A complex
|
|
7
|
+
* number is rectangular `{ re, im }`; the polar view (modulus r, argument θ) is
|
|
8
|
+
* derived, exactly the (x, y) ↔ (r, θ) bridge the vector labs already teach.
|
|
9
|
+
*
|
|
10
|
+
* Engineered for CORRECTNESS + SAFETY (no NaN spirals, no overflow, no runaway
|
|
11
|
+
* loops):
|
|
12
|
+
* • modulus uses Math.hypot (no re²+im² overflow);
|
|
13
|
+
* • division uses Smith's algorithm (scale by the larger term, avoids overflow
|
|
14
|
+
* / underflow), with a near-zero-denominator guard;
|
|
15
|
+
* • integer powers use exponentiation-by-squaring, |n| capped (MAX_POW), with a
|
|
16
|
+
* finiteness guard so r^n that overflows returns an explicit ∞, not garbage;
|
|
17
|
+
* • iⁿ is computed EXACTLY from n mod 4 (no float drift in the i, −1, −i, 1 cycle);
|
|
18
|
+
* • rootsOfUnity / nthRoots cap n (MAX_ROOTS) so an author can't request a
|
|
19
|
+
* billion-element array.
|
|
20
|
+
*/
|
|
21
|
+
interface Complex {
|
|
22
|
+
re: number;
|
|
23
|
+
im: number;
|
|
24
|
+
}
|
|
25
|
+
declare const TWO_PI: number;
|
|
26
|
+
declare const RAD2DEG: number;
|
|
27
|
+
declare const DEG2RAD: number;
|
|
28
|
+
/** Hard caps so an authored value can never blow memory or hang a loop. */
|
|
29
|
+
declare const MAX_POW = 1024;
|
|
30
|
+
declare const MAX_ROOTS = 360;
|
|
31
|
+
declare const cx: (re: number, im?: number) => Complex;
|
|
32
|
+
declare const ZERO: Complex;
|
|
33
|
+
declare const ONE: Complex;
|
|
34
|
+
declare const I: Complex;
|
|
35
|
+
declare const isFiniteC: (z: Complex) => boolean;
|
|
36
|
+
declare const add: (a: Complex, b: Complex) => Complex;
|
|
37
|
+
declare const sub: (a: Complex, b: Complex) => Complex;
|
|
38
|
+
declare const neg: (a: Complex) => Complex;
|
|
39
|
+
declare const conj: (a: Complex) => Complex;
|
|
40
|
+
declare const scale: (a: Complex, k: number) => Complex;
|
|
41
|
+
/** (a+bi)(c+di) = (ac − bd) + (ad + bc)i. */
|
|
42
|
+
declare const mul: (a: Complex, b: Complex) => Complex;
|
|
43
|
+
/**
|
|
44
|
+
* Complex division via Smith's algorithm: divide through by the LARGER of the
|
|
45
|
+
* denominator's components so the intermediate ratio stays in [−1, 1] (no
|
|
46
|
+
* overflow when |b| is huge, no underflow when tiny). Returns an ∞/NaN complex
|
|
47
|
+
* for a (near-)zero denominator rather than throwing.
|
|
48
|
+
*/
|
|
49
|
+
declare function div(a: Complex, b: Complex): Complex;
|
|
50
|
+
/** Modulus |z| = √(re² + im²), via hypot so large components don't overflow. */
|
|
51
|
+
declare const abs: (z: Complex) => number;
|
|
52
|
+
/** Argument arg(z) in RADIANS, in (−π, π]. arg(0) = 0 by convention. */
|
|
53
|
+
declare const arg: (z: Complex) => number;
|
|
54
|
+
/** Argument in DEGREES, in (−180, 180]. */
|
|
55
|
+
declare const argDeg: (z: Complex) => number;
|
|
56
|
+
/** Polar → rectangular: r·e^{iθ} = r(cosθ + i sinθ), θ in radians. */
|
|
57
|
+
declare const fromPolar: (r: number, theta: number) => Complex;
|
|
58
|
+
/** Rectangular → polar { r, theta(rad) }. */
|
|
59
|
+
declare const toPolar: (z: Complex) => {
|
|
60
|
+
r: number;
|
|
61
|
+
theta: number;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* iⁿ for any integer n, EXACTLY (no De Moivre float drift): the 4-cycle
|
|
65
|
+
* 1, i, −1, −i. Negative n handled by the (n mod 4 + 4) mod 4 normalisation.
|
|
66
|
+
*/
|
|
67
|
+
declare function iPow(n: number): Complex;
|
|
68
|
+
/**
|
|
69
|
+
* zⁿ for an INTEGER n via exponentiation-by-squaring (negative n inverts).
|
|
70
|
+
* |n| is capped at MAX_POW; an overflowing magnitude returns an explicit ∞
|
|
71
|
+
* complex (finite check) instead of looping into garbage.
|
|
72
|
+
*/
|
|
73
|
+
declare function powInt(z: Complex, n: number): Complex;
|
|
74
|
+
/**
|
|
75
|
+
* The n nth-roots of UNITY: e^{2πik/n}, k = 0…n−1 (so ω = roots[1] is the
|
|
76
|
+
* primitive root). For n = 2 → {1, −1}; n = 3 → {1, ω, ω²}; n = 4 → {1, i, −1, −i}.
|
|
77
|
+
* n is clamped to [1, MAX_ROOTS]. The k = n/2 (real −1) and k = 0 (real 1) entries
|
|
78
|
+
* are snapped to exact values so labels read cleanly.
|
|
79
|
+
*/
|
|
80
|
+
declare function rootsOfUnity(n: number): Complex[];
|
|
81
|
+
/** The n nth-roots of any z: |z|^{1/n} · e^{i(arg z + 2πk)/n}, k = 0…n−1. */
|
|
82
|
+
declare function nthRoots(z: Complex, n: number): Complex[];
|
|
83
|
+
/** The primitive nth root of unity ω (default the CUBE root, n = 3): e^{2πi/n}.
|
|
84
|
+
* For n = 3: ω = −½ + (√3/2)i, with ω³ = 1 and 1 + ω + ω² = 0. */
|
|
85
|
+
declare const omega: (n?: number) => Complex;
|
|
86
|
+
/** Equal within a tolerance (default 1e-9), on both components. */
|
|
87
|
+
declare const eq: (a: Complex, b: Complex, eps?: number) => boolean;
|
|
88
|
+
/** Plain string, e.g. "3 − 2i", "i", "−1", "0", "2i". */
|
|
89
|
+
declare function toStr(z: Complex, dp?: number): string;
|
|
90
|
+
/** LaTeX form for <Tex> (uses real minus signs, "i"). */
|
|
91
|
+
declare function toTex(z: Complex, dp?: number): string;
|
|
92
|
+
//#endregion
|
|
93
|
+
export { Complex, complex_d_exports };
|