eml-stdlib 0.4.0__py3-none-any.whl

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 (185) hide show
  1. eml_stdlib/__init__.py +81 -0
  2. eml_stdlib/ballistics/air_density.eml +73 -0
  3. eml_stdlib/ballistics/ballistic_solver.eml +102 -0
  4. eml_stdlib/ballistics/coriolis.eml +60 -0
  5. eml_stdlib/ballistics/drag.eml +44 -0
  6. eml_stdlib/ballistics/gravity.eml +52 -0
  7. eml_stdlib/ballistics/muzzle_velocity.eml +42 -0
  8. eml_stdlib/ballistics/spin_drift.eml +60 -0
  9. eml_stdlib/ballistics/time_of_flight.eml +79 -0
  10. eml_stdlib/ballistics/wind.eml +58 -0
  11. eml_stdlib/biology/abilities/ballistic_armor.eml +61 -0
  12. eml_stdlib/biology/abilities/bite_force.eml +48 -0
  13. eml_stdlib/biology/abilities/chromatophore.eml +50 -0
  14. eml_stdlib/biology/abilities/discharge.eml +45 -0
  15. eml_stdlib/biology/abilities/elastic_energy.eml +42 -0
  16. eml_stdlib/biology/abilities/locomotion.eml +50 -0
  17. eml_stdlib/biology/abilities/muscle_power.eml +47 -0
  18. eml_stdlib/biology/abilities/sprint.eml +36 -0
  19. eml_stdlib/biology/abilities/texture_match.eml +49 -0
  20. eml_stdlib/biology/abilities/toxin.eml +44 -0
  21. eml_stdlib/biology/cone_l.eml +36 -0
  22. eml_stdlib/biology/cone_s.eml +32 -0
  23. eml_stdlib/biology/cryptochrome.eml +44 -0
  24. eml_stdlib/biology/geomagnetic_field.eml +32 -0
  25. eml_stdlib/biology/goldman_equation.eml +41 -0
  26. eml_stdlib/biology/hill_equation.eml +65 -0
  27. eml_stdlib/biology/hodgkin_huxley.eml +108 -0
  28. eml_stdlib/biology/michaelis_menten.eml +65 -0
  29. eml_stdlib/biology/plume_diffusion.eml +47 -0
  30. eml_stdlib/biology/receptor_binding.eml +35 -0
  31. eml_stdlib/biology/rod_sensitivity.eml +38 -0
  32. eml_stdlib/biology/tapetum.eml +70 -0
  33. eml_stdlib/carriers/acoustic_cloak.eml +56 -0
  34. eml_stdlib/carriers/ferron_emission.eml +55 -0
  35. eml_stdlib/carriers/ferron_logic.eml +45 -0
  36. eml_stdlib/carriers/ferron_propagation.eml +69 -0
  37. eml_stdlib/carriers/mach_zehnder.eml +52 -0
  38. eml_stdlib/carriers/magnon_dispersion.eml +57 -0
  39. eml_stdlib/carriers/magnon_logic.eml +45 -0
  40. eml_stdlib/carriers/optical_neuron.eml +55 -0
  41. eml_stdlib/carriers/phonon_bandgap.eml +54 -0
  42. eml_stdlib/carriers/ring_resonator.eml +48 -0
  43. eml_stdlib/carriers/spin_torque.eml +61 -0
  44. eml_stdlib/carriers/thermal_rectifier.eml +63 -0
  45. eml_stdlib/catalog.json +4209 -0
  46. eml_stdlib/circuits/buck_converter.eml +74 -0
  47. eml_stdlib/circuits/cmos_inverter.eml +75 -0
  48. eml_stdlib/circuits/h_bridge.eml +69 -0
  49. eml_stdlib/circuits/ldo.eml +66 -0
  50. eml_stdlib/circuits/mosfet_iv.eml +59 -0
  51. eml_stdlib/circuits/pll_loop.eml +63 -0
  52. eml_stdlib/circuits/rc_filter.eml +98 -0
  53. eml_stdlib/circuits/voltage_divider.eml +68 -0
  54. eml_stdlib/control/bangbang.eml +34 -0
  55. eml_stdlib/control/deadband.eml +28 -0
  56. eml_stdlib/control/hysteresis.eml +28 -0
  57. eml_stdlib/control/kalman_1d.eml +53 -0
  58. eml_stdlib/control/lqr_1d.eml +47 -0
  59. eml_stdlib/control/pid.eml +38 -0
  60. eml_stdlib/gaming/animation/bounce.eml +39 -0
  61. eml_stdlib/gaming/animation/ease_in.eml +27 -0
  62. eml_stdlib/gaming/animation/ease_in_out.eml +29 -0
  63. eml_stdlib/gaming/animation/ease_out.eml +27 -0
  64. eml_stdlib/gaming/animation/ik_2bone.eml +57 -0
  65. eml_stdlib/gaming/animation/spring.eml +39 -0
  66. eml_stdlib/gaming/audio/distance_attenuation.eml +50 -0
  67. eml_stdlib/gaming/audio/doppler.eml +39 -0
  68. eml_stdlib/gaming/audio/lowpass_audio.eml +32 -0
  69. eml_stdlib/gaming/audio/reverb_delay.eml +41 -0
  70. eml_stdlib/gaming/camera/dof_blur.eml +30 -0
  71. eml_stdlib/gaming/camera/fov_projection.eml +47 -0
  72. eml_stdlib/gaming/camera/orbit.eml +48 -0
  73. eml_stdlib/gaming/camera/shake.eml +20 -0
  74. eml_stdlib/gaming/lighting/ambient_occlusion.eml +40 -0
  75. eml_stdlib/gaming/lighting/area_light.eml +50 -0
  76. eml_stdlib/gaming/lighting/fog_exp.eml +28 -0
  77. eml_stdlib/gaming/lighting/fog_exp2.eml +30 -0
  78. eml_stdlib/gaming/lighting/point_light.eml +33 -0
  79. eml_stdlib/gaming/lighting/spot_light.eml +43 -0
  80. eml_stdlib/gaming/noise/fbm.eml +65 -0
  81. eml_stdlib/gaming/noise/perlin_2d.eml +65 -0
  82. eml_stdlib/gaming/noise/perlin_3d.eml +63 -0
  83. eml_stdlib/gaming/noise/simplex_2d.eml +67 -0
  84. eml_stdlib/gaming/noise/turbulence.eml +46 -0
  85. eml_stdlib/gaming/noise/value_noise.eml +45 -0
  86. eml_stdlib/gaming/noise/voronoi_2d.eml +83 -0
  87. eml_stdlib/gaming/noise/white_noise.eml +47 -0
  88. eml_stdlib/gaming/noise/worley.eml +79 -0
  89. eml_stdlib/gaming/particles/drag.eml +30 -0
  90. eml_stdlib/gaming/particles/emitter_radial.eml +35 -0
  91. eml_stdlib/gaming/particles/fade.eml +36 -0
  92. eml_stdlib/gaming/particles/gravity_particle.eml +32 -0
  93. eml_stdlib/gaming/particles/size_over_life.eml +28 -0
  94. eml_stdlib/gaming/physics/aabb_overlap.eml +38 -0
  95. eml_stdlib/gaming/physics/buoyancy.eml +43 -0
  96. eml_stdlib/gaming/physics/circle_collision.eml +46 -0
  97. eml_stdlib/gaming/physics/impulse_resolve.eml +39 -0
  98. eml_stdlib/gaming/physics/rigid_body_2d.eml +61 -0
  99. eml_stdlib/gaming/physics/spring_damper.eml +30 -0
  100. eml_stdlib/gaming/physics/verlet.eml +29 -0
  101. eml_stdlib/gaming/shading/fresnel.eml +57 -0
  102. eml_stdlib/gaming/shading/matcap.eml +34 -0
  103. eml_stdlib/gaming/shading/pbr_diffuse.eml +41 -0
  104. eml_stdlib/gaming/shading/pbr_specular.eml +75 -0
  105. eml_stdlib/gaming/shading/subsurface.eml +52 -0
  106. eml_stdlib/gaming/shading/toon.eml +30 -0
  107. eml_stdlib/gaming/terrain/biome_select.eml +41 -0
  108. eml_stdlib/gaming/terrain/cliff_detect.eml +35 -0
  109. eml_stdlib/gaming/terrain/erosion_hydraulic.eml +57 -0
  110. eml_stdlib/gaming/terrain/erosion_thermal.eml +44 -0
  111. eml_stdlib/gaming/terrain/heightmap.eml +33 -0
  112. eml_stdlib/gaming/textures/brick.eml +27 -0
  113. eml_stdlib/gaming/textures/caustics.eml +25 -0
  114. eml_stdlib/gaming/textures/checkerboard.eml +27 -0
  115. eml_stdlib/gaming/textures/fire.eml +26 -0
  116. eml_stdlib/gaming/textures/marble.eml +24 -0
  117. eml_stdlib/gaming/textures/rust.eml +23 -0
  118. eml_stdlib/gaming/textures/water_surface.eml +49 -0
  119. eml_stdlib/gaming/textures/wood.eml +41 -0
  120. eml_stdlib/math/abs.eml +45 -0
  121. eml_stdlib/math/atan.eml +32 -0
  122. eml_stdlib/math/atan2.eml +61 -0
  123. eml_stdlib/math/bessel_j0.eml +65 -0
  124. eml_stdlib/math/cos.eml +42 -0
  125. eml_stdlib/math/cosh.eml +24 -0
  126. eml_stdlib/math/erf.eml +66 -0
  127. eml_stdlib/math/exp.eml +49 -0
  128. eml_stdlib/math/gamma.eml +55 -0
  129. eml_stdlib/math/gaussian.eml +18 -0
  130. eml_stdlib/math/log.eml +59 -0
  131. eml_stdlib/math/pow.eml +51 -0
  132. eml_stdlib/math/relu.eml +63 -0
  133. eml_stdlib/math/sigmoid.eml +21 -0
  134. eml_stdlib/math/sin.eml +37 -0
  135. eml_stdlib/math/sinh.eml +24 -0
  136. eml_stdlib/math/softmax.eml +87 -0
  137. eml_stdlib/math/sqrt.eml +46 -0
  138. eml_stdlib/math/tan.eml +36 -0
  139. eml_stdlib/math/tanh.eml +54 -0
  140. eml_stdlib/ml/attention.eml +70 -0
  141. eml_stdlib/ml/cross_entropy.eml +85 -0
  142. eml_stdlib/ml/gelu.eml +51 -0
  143. eml_stdlib/ml/layernorm.eml +49 -0
  144. eml_stdlib/ml/leaky_relu.eml +51 -0
  145. eml_stdlib/ml/relu.eml +63 -0
  146. eml_stdlib/ml/rotary_embed.eml +64 -0
  147. eml_stdlib/ml/silu.eml +40 -0
  148. eml_stdlib/ml/softmax.eml +87 -0
  149. eml_stdlib/physics/coulomb.eml +48 -0
  150. eml_stdlib/physics/damped_oscillator.eml +20 -0
  151. eml_stdlib/physics/diffusion.eml +45 -0
  152. eml_stdlib/physics/gravity.eml +60 -0
  153. eml_stdlib/physics/hooke.eml +56 -0
  154. eml_stdlib/physics/navier_stokes_1d.eml +57 -0
  155. eml_stdlib/physics/planck_radiation.eml +77 -0
  156. eml_stdlib/physics/stefan_boltzmann.eml +75 -0
  157. eml_stdlib/physics/wave_propagation.eml +52 -0
  158. eml_stdlib/quantum/cnot.eml +72 -0
  159. eml_stdlib/quantum/grover_oracle.eml +69 -0
  160. eml_stdlib/quantum/hadamard.eml +73 -0
  161. eml_stdlib/quantum/pauli_x.eml +29 -0
  162. eml_stdlib/quantum/pauli_z.eml +29 -0
  163. eml_stdlib/quantum/phase_gate.eml +76 -0
  164. eml_stdlib/quantum/rotation_rz.eml +92 -0
  165. eml_stdlib/sensors/accelerometer.eml +59 -0
  166. eml_stdlib/sensors/hall_effect.eml +42 -0
  167. eml_stdlib/sensors/photodetector.eml +58 -0
  168. eml_stdlib/sensors/rtd.eml +57 -0
  169. eml_stdlib/sensors/strain_gauge.eml +63 -0
  170. eml_stdlib/sensors/thermistor.eml +71 -0
  171. eml_stdlib/signal/bandpass.eml +39 -0
  172. eml_stdlib/signal/chirp.eml +42 -0
  173. eml_stdlib/signal/dft_single.eml +30 -0
  174. eml_stdlib/signal/fft_butterfly.eml +36 -0
  175. eml_stdlib/signal/highpass.eml +45 -0
  176. eml_stdlib/signal/lowpass.eml +49 -0
  177. eml_stdlib/signal/matched_filter.eml +48 -0
  178. eml_stdlib/signal/notch_filter.eml +47 -0
  179. eml_stdlib/signal/window_hamming.eml +47 -0
  180. eml_stdlib/signal/window_hann.eml +50 -0
  181. eml_stdlib-0.4.0.dist-info/METADATA +453 -0
  182. eml_stdlib-0.4.0.dist-info/RECORD +185 -0
  183. eml_stdlib-0.4.0.dist-info/WHEEL +5 -0
  184. eml_stdlib-0.4.0.dist-info/licenses/LICENSE +21 -0
  185. eml_stdlib-0.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,53 @@
1
+ // kalman_1d.eml -- one-step 1-D Kalman filter.
2
+ //
3
+ // State: estimate (scalar), variance P (scalar)
4
+ // Inputs: measurement z, measurement variance R, process variance Q
5
+ //
6
+ // The two functions update / predict the state. Caller chains them
7
+ // each frame. All chain order 0 -- pure rational arithmetic.
8
+ //
9
+ // The 1-D Kalman is the workhorse for IMU heading, RC battery state
10
+ // of charge, and any single-channel "noisy sensor + smooth dynamics"
11
+ // fusion.
12
+
13
+ module kalman_1d;
14
+
15
+ // Predict step: drift the variance forward by Q.
16
+ @verify(lean, theorem = "kalman1d_predict_variance_grows")
17
+ fn kalman1d_predict(estimate: Real, p: Real, q: Real) -> (Real, Real)
18
+ where chain_order <= 0
19
+ requires (p >= 0.0)
20
+ requires (q >= 0.0)
21
+ {
22
+ (estimate, p + q)
23
+ }
24
+
25
+ // Update step: combine with measurement z.
26
+ @verify(lean, theorem = "kalman1d_update_variance_shrinks")
27
+ fn kalman1d_update(estimate: Real, p: Real, z: Real, r: Real) -> (Real, Real)
28
+ where chain_order <= 0
29
+ requires (p >= 0.0)
30
+ requires (r > 0.0)
31
+ {
32
+ let k = p / (p + r);
33
+ let new_est = estimate + k * (z - estimate);
34
+ let new_p = (1.0 - k) * p;
35
+ (new_est, new_p)
36
+ }
37
+
38
+ // Combined predict-then-update in one call -- the form most
39
+ // users want when running on a fixed sample rate.
40
+ @verify(lean, theorem = "kalman1d_step_variance_bounded")
41
+ fn kalman1d_step(estimate: Real, p: Real, z: Real, q: Real, r: Real)
42
+ -> (Real, Real)
43
+ where chain_order <= 0
44
+ requires (p >= 0.0)
45
+ requires (q >= 0.0)
46
+ requires (r > 0.0)
47
+ {
48
+ let p_pred = p + q;
49
+ let k = p_pred / (p_pred + r);
50
+ let new_est = estimate + k * (z - estimate);
51
+ let new_p = (1.0 - k) * p_pred;
52
+ (new_est, new_p)
53
+ }
@@ -0,0 +1,47 @@
1
+ // lqr_1d.eml -- 1-D infinite-horizon LQR.
2
+ //
3
+ // For a scalar plant
4
+ // x' = a*x + b*u
5
+ // with cost J = sum q*x^2 + r*u^2
6
+ // the optimal control is u = -k*x with
7
+ // k = (b*p) / r
8
+ // p = solution of the algebraic Riccati equation
9
+ // p = q + a^2*p - (a*b*p)^2 / (r + b^2*p)
10
+ //
11
+ // For the closed-form 1-D scalar Riccati this simplifies to the
12
+ // quadratic
13
+ // b^2 * p^2 - (b^2 * q / r + a^2 - 1) * p - q = 0
14
+ // which has one positive root.
15
+
16
+ module lqr_1d;
17
+
18
+ // Closed-form solution of the scalar discrete-time ARE,
19
+ // returning the Riccati P > 0.
20
+ @verify(lean, theorem = "lqr_1d_riccati_positive")
21
+ fn riccati(a: Real, b: Real, q: Real, r: Real) -> Real
22
+ where chain_order <= 1,
23
+ domain: r > 0.0 && q >= 0.0 && b != 0.0
24
+ ensures (result >= 0.0)
25
+ {
26
+ let alpha = b * b / r;
27
+ let beta = a * a - 1.0;
28
+ let disc = (beta + alpha * q) * (beta + alpha * q) + 4.0 * alpha * q;
29
+ (beta + alpha * q + sqrt(disc)) / (2.0 * alpha)
30
+ }
31
+
32
+ // Optimal feedback gain k from the Riccati P.
33
+ @verify(lean, theorem = "lqr_1d_gain_positive_for_positive_b")
34
+ fn lqr_gain(b: Real, p: Real, r: Real) -> Real
35
+ where chain_order <= 0,
36
+ domain: r > 0.0 && p >= 0.0
37
+ {
38
+ b * p / r
39
+ }
40
+
41
+ // Closed-loop control law u = -k * x.
42
+ @verify(lean, theorem = "lqr_1d_control_proportional_to_state")
43
+ fn lqr_control(x: Real, k: Real) -> Real
44
+ where chain_order <= 0
45
+ {
46
+ -k * x
47
+ }
@@ -0,0 +1,38 @@
1
+ // pid_controller.eml -- the textbook PID controller.
2
+ //
3
+ // output = Kp * error + Ki * integral + Kd * derivative
4
+ //
5
+ // Universal control loop: heating, motors, robots, drones,
6
+ // rockets. Chain order 0 (a linear combination of the inputs).
7
+ // The interesting part is the @verify contract: the output is
8
+ // always clamped to the actuator's physical range.
9
+ //
10
+ // Phase F migration: the three single-variable input bounds that
11
+ // were previously expressed as `requires (abs(x) <= 100.0)` clauses
12
+ // are now refinement types directly on the parameters. Semantics
13
+ // are equivalent -- every backend lowers refinements to the same
14
+ // guard form (`assert`, `require`, hypothesis, ...) the old
15
+ // `requires` produced -- but the contract now lives at the type,
16
+ // where dimensional + value bounds belong, instead of trailing
17
+ // the signature.
18
+
19
+ module pid_controller;
20
+
21
+ const Kp: Real = 1.5
22
+ const Ki: Real = 0.4
23
+ const Kd: Real = 0.05
24
+
25
+ const OUT_MIN: Real = -1.0
26
+ const OUT_MAX: Real = 1.0
27
+
28
+ @verify(lean, theorem = "pid_output_clamped")
29
+ fn pid(error: Real{e | abs(e) <= 100.0},
30
+ integral: Real{i | abs(i) <= 100.0},
31
+ derivative: Real{d | abs(d) <= 100.0}) -> Real
32
+ where chain_order <= 0
33
+ ensures (result >= OUT_MIN)
34
+ ensures (result <= OUT_MAX)
35
+ {
36
+ let raw = Kp * error + Ki * integral + Kd * derivative;
37
+ clamp(raw, OUT_MIN, OUT_MAX)
38
+ }
@@ -0,0 +1,39 @@
1
+ // bounce.eml -- piecewise parabolic bounce-out curve.
2
+ //
3
+ // The standard easing-functions bounce-out: four parabolic
4
+ // segments of decreasing amplitude. Output ∈ [0, 1].
5
+
6
+ module bounce;
7
+
8
+ @verify(lean, theorem = "bounce_out_in_unit_interval")
9
+ fn bounce_out(t: Real) -> Real
10
+ where chain_order <= 0
11
+ requires (t >= 0.0)
12
+ requires (t <= 1.0)
13
+ ensures (result >= 0.0)
14
+ ensures (result <= 1.0)
15
+ {
16
+ if t < 0.36364 { // 1 / 2.75
17
+ 7.5625 * t * t
18
+ } else if t < 0.72727 { // 2 / 2.75
19
+ let u: Real = t - 0.54545; // 1.5 / 2.75
20
+ 7.5625 * u * u + 0.75
21
+ } else if t < 0.90909 { // 2.5 / 2.75
22
+ let u: Real = t - 0.81818; // 2.25 / 2.75
23
+ 7.5625 * u * u + 0.9375
24
+ } else {
25
+ let u: Real = t - 0.95455; // 2.625 / 2.75
26
+ 7.5625 * u * u + 0.984375
27
+ }
28
+ }
29
+
30
+ @verify(lean, theorem = "bounce_in_in_unit_interval")
31
+ fn bounce_in(t: Real) -> Real
32
+ where chain_order <= 0
33
+ requires (t >= 0.0)
34
+ requires (t <= 1.0)
35
+ ensures (result >= 0.0)
36
+ ensures (result <= 1.0)
37
+ {
38
+ 1.0 - bounce_out(1.0 - t)
39
+ }
@@ -0,0 +1,27 @@
1
+ // ease_in.eml -- quadratic ease-in: t².
2
+ //
3
+ // t ∈ [0, 1] → result ∈ [0, 1], starts slow, accelerates.
4
+
5
+ module ease_in;
6
+
7
+ @verify(lean, theorem = "ease_in_in_unit_interval")
8
+ fn ease_in_quad(t: Real) -> Real
9
+ where chain_order <= 0
10
+ requires (t >= 0.0)
11
+ requires (t <= 1.0)
12
+ ensures (result >= 0.0)
13
+ ensures (result <= 1.0)
14
+ {
15
+ t * t
16
+ }
17
+
18
+ @verify(lean, theorem = "ease_in_cubic_in_unit_interval")
19
+ fn ease_in_cubic(t: Real) -> Real
20
+ where chain_order <= 0
21
+ requires (t >= 0.0)
22
+ requires (t <= 1.0)
23
+ ensures (result >= 0.0)
24
+ ensures (result <= 1.0)
25
+ {
26
+ t * t * t
27
+ }
@@ -0,0 +1,29 @@
1
+ // ease_in_out.eml -- smoothstep: 3t² - 2t³.
2
+
3
+ module ease_in_out;
4
+
5
+ @verify(lean, theorem = "smoothstep_in_unit_interval")
6
+ fn smoothstep(t: Real) -> Real
7
+ where chain_order <= 0
8
+ requires (t >= 0.0)
9
+ requires (t <= 1.0)
10
+ ensures (result >= 0.0)
11
+ ensures (result <= 1.0)
12
+ {
13
+ 3.0 * t * t - 2.0 * t * t * t
14
+ }
15
+
16
+ // Quintic smootherstep — 6t⁵ - 15t⁴ + 10t³, C² continuous.
17
+ @verify(lean, theorem = "smootherstep_in_unit_interval")
18
+ fn smootherstep(t: Real) -> Real
19
+ where chain_order <= 0
20
+ requires (t >= 0.0)
21
+ requires (t <= 1.0)
22
+ ensures (result >= 0.0)
23
+ ensures (result <= 1.0)
24
+ {
25
+ let t3: Real = t * t * t;
26
+ let t4: Real = t3 * t;
27
+ let t5: Real = t4 * t;
28
+ 6.0 * t5 - 15.0 * t4 + 10.0 * t3
29
+ }
@@ -0,0 +1,27 @@
1
+ // ease_out.eml -- quadratic ease-out: 1 - (1 - t)².
2
+
3
+ module ease_out;
4
+
5
+ @verify(lean, theorem = "ease_out_in_unit_interval")
6
+ fn ease_out_quad(t: Real) -> Real
7
+ where chain_order <= 0
8
+ requires (t >= 0.0)
9
+ requires (t <= 1.0)
10
+ ensures (result >= 0.0)
11
+ ensures (result <= 1.0)
12
+ {
13
+ let one_minus_t: Real = 1.0 - t;
14
+ 1.0 - one_minus_t * one_minus_t
15
+ }
16
+
17
+ @verify(lean, theorem = "ease_out_cubic_in_unit_interval")
18
+ fn ease_out_cubic(t: Real) -> Real
19
+ where chain_order <= 0
20
+ requires (t >= 0.0)
21
+ requires (t <= 1.0)
22
+ ensures (result >= 0.0)
23
+ ensures (result <= 1.0)
24
+ {
25
+ let one_minus_t: Real = 1.0 - t;
26
+ 1.0 - one_minus_t * one_minus_t * one_minus_t
27
+ }
@@ -0,0 +1,57 @@
1
+ // ik_2bone.eml -- two-bone inverse kinematics via law of cosines.
2
+ //
3
+ // Given an upper bone of length L1 and a lower bone of length L2,
4
+ // reach a target at distance D from the shoulder. Compute the
5
+ // shoulder + elbow joint angles:
6
+ //
7
+ // cos(elbow) = (L1² + L2² - D²) / (2 * L1 * L2)
8
+ // cos(α) = (L1² + D² - L2²) / (2 * L1 * D) // shoulder, target-relative
9
+ //
10
+ // Returns the elbow angle (rad) and the shoulder offset angle (rad)
11
+ // as separate functions so the caller can compose with the
12
+ // shoulder-to-target azimuth.
13
+
14
+ module ik_2bone;
15
+
16
+ @verify(lean, theorem = "elbow_angle_in_pi_band")
17
+ fn elbow_angle(l1: Real, l2: Real, distance: Real) -> Real
18
+ where chain_order <= 1,
19
+ domain: l1 > 0.0 && l2 > 0.0 && distance > 0.0
20
+ ensures (result >= 0.0)
21
+ ensures (result <= 3.141592653589793)
22
+ {
23
+ let cos_e: Real = clamp(
24
+ (l1 * l1 + l2 * l2 - distance * distance) / (2.0 * l1 * l2),
25
+ -1.0, 1.0
26
+ );
27
+ acos(cos_e)
28
+ }
29
+
30
+ @verify(lean, theorem = "shoulder_angle_in_half_pi_band")
31
+ fn shoulder_offset(l1: Real, l2: Real, distance: Real) -> Real
32
+ where chain_order <= 1,
33
+ domain: l1 > 0.0 && l2 > 0.0 && distance > 0.0
34
+ ensures (result >= 0.0)
35
+ ensures (result <= 1.5707963267948966)
36
+ {
37
+ let cos_a: Real = clamp(
38
+ (l1 * l1 + distance * distance - l2 * l2) / (2.0 * l1 * distance),
39
+ -1.0, 1.0
40
+ );
41
+ acos(cos_a)
42
+ }
43
+
44
+ // Reachability: returns 1.0 if the target is reachable, 0.0 if not.
45
+ @verify(lean, theorem = "ik_reachable_in_zero_one")
46
+ fn reachable(l1: Real, l2: Real, distance: Real) -> Real
47
+ where chain_order <= 0,
48
+ domain: l1 > 0.0 && l2 > 0.0 && distance >= 0.0
49
+ ensures (result >= 0.0)
50
+ ensures (result <= 1.0)
51
+ {
52
+ let max_reach: Real = l1 + l2;
53
+ let min_reach: Real = abs(l1 - l2);
54
+ if distance > max_reach { 0.0 }
55
+ else if distance < min_reach { 0.0 }
56
+ else { 1.0 }
57
+ }
@@ -0,0 +1,39 @@
1
+ // spring.eml -- damped harmonic oscillator response.
2
+ //
3
+ // x(t) = A * exp(-ζ ω t) * cos(ω_d t + φ)
4
+ //
5
+ // where ω is natural frequency, ζ damping ratio, ω_d = ω√(1-ζ²)
6
+ // the damped frequency. Underdamped (ζ < 1) is the case actually
7
+ // useful for animation; critically damped (ζ = 1) is a smooth
8
+ // follow.
9
+
10
+ module spring;
11
+
12
+ @verify(lean, theorem = "spring_underdamped_signed")
13
+ fn underdamped(amplitude: Real, omega: Real, damping_ratio: Real,
14
+ phase: Real, t_s: Real) -> Real
15
+ where chain_order <= 1,
16
+ domain: omega > 0.0 && damping_ratio >= 0.0 && damping_ratio < 1.0 && t_s >= 0.0
17
+ {
18
+ let omega_d: Real = omega * sqrt(1.0 - damping_ratio * damping_ratio);
19
+ amplitude * exp(-damping_ratio * omega * t_s) * cos(omega_d * t_s + phase)
20
+ }
21
+
22
+ // Critically damped: x(t) = A * (1 + ω t) * exp(-ω t)
23
+ @verify(lean, theorem = "spring_critical_signed")
24
+ fn critically_damped(amplitude: Real, omega: Real, t_s: Real) -> Real
25
+ where chain_order <= 1,
26
+ domain: omega > 0.0 && t_s >= 0.0
27
+ {
28
+ amplitude * (1.0 + omega * t_s) * exp(-omega * t_s)
29
+ }
30
+
31
+ // Time constant τ = 1/(ζω) for underdamped exponential envelope.
32
+ @verify(lean, theorem = "spring_tau_positive")
33
+ fn time_constant(omega: Real, damping_ratio: Real) -> Real
34
+ where chain_order <= 0,
35
+ domain: omega > 0.0 && damping_ratio > 0.0
36
+ ensures (result > 0.0)
37
+ {
38
+ 1.0 / (damping_ratio * omega)
39
+ }
@@ -0,0 +1,50 @@
1
+ // distance_attenuation.eml -- 3D audio falloff models.
2
+ //
3
+ // Three common laws:
4
+ // inverse: a = ref_dist / max(d, ref_dist)
5
+ // inv_square: a = ref_dist² / max(d, ref_dist)² (physical)
6
+ // linear: a = max(0, 1 - (d - ref_dist) / (max_dist - ref_dist))
7
+ //
8
+ // Output ∈ [0, 1]: 1 = full volume at ref_dist, 0 = silent at max_dist.
9
+
10
+ module distance_attenuation;
11
+
12
+ @verify(lean, theorem = "audio_attenuation_inverse_in_unit_interval")
13
+ fn inverse(distance_m: Real, ref_distance_m: Real) -> Real
14
+ where chain_order <= 0,
15
+ domain: distance_m >= 0.0 && ref_distance_m > 0.0
16
+ ensures (result >= 0.0)
17
+ ensures (result <= 1.0)
18
+ {
19
+ let d: Real = max(distance_m, ref_distance_m);
20
+ ref_distance_m / d
21
+ }
22
+
23
+ @verify(lean, theorem = "audio_attenuation_inverse_square_in_unit_interval")
24
+ fn inverse_square(distance_m: Real, ref_distance_m: Real) -> Real
25
+ where chain_order <= 0,
26
+ domain: distance_m >= 0.0 && ref_distance_m > 0.0
27
+ ensures (result >= 0.0)
28
+ ensures (result <= 1.0)
29
+ {
30
+ let d: Real = max(distance_m, ref_distance_m);
31
+ let ratio: Real = ref_distance_m / d;
32
+ ratio * ratio
33
+ }
34
+
35
+ @verify(lean, theorem = "audio_attenuation_linear_in_unit_interval")
36
+ fn linear(distance_m: Real, ref_distance_m: Real, max_distance_m: Real) -> Real
37
+ where chain_order <= 0,
38
+ domain: distance_m >= 0.0 && max_distance_m > ref_distance_m
39
+ ensures (result >= 0.0)
40
+ ensures (result <= 1.0)
41
+ {
42
+ if distance_m <= ref_distance_m {
43
+ 1.0
44
+ } else if distance_m >= max_distance_m {
45
+ 0.0
46
+ } else {
47
+ clamp(1.0 - (distance_m - ref_distance_m) / (max_distance_m - ref_distance_m),
48
+ 0.0, 1.0)
49
+ }
50
+ }
@@ -0,0 +1,39 @@
1
+ // doppler.eml -- Doppler frequency shift.
2
+ //
3
+ // f_observed = f_source * (v_sound + v_listener) / (v_sound + v_source)
4
+ //
5
+ // Sign convention: velocities are positive when the entity moves
6
+ // AWAY FROM the listener / source (for the source) or TOWARD the
7
+ // source (for the listener). Game engines typically supply velocity
8
+ // vectors and project onto the source→listener direction.
9
+
10
+ module doppler;
11
+
12
+ const V_SOUND_AIR: Real = 343.0 // m/s
13
+
14
+ @verify(lean, theorem = "doppler_observed_freq_positive")
15
+ fn observed_frequency(f_source: Real, v_sound: Real,
16
+ v_listener_toward_source: Real,
17
+ v_source_away_from_listener: Real) -> Real
18
+ where chain_order <= 0,
19
+ domain: v_sound > 0.0
20
+ requires (f_source >= 0.0)
21
+ requires (v_sound + v_source_away_from_listener > 0.0)
22
+ ensures (result >= 0.0)
23
+ {
24
+ f_source * (v_sound + v_listener_toward_source)
25
+ / (v_sound + v_source_away_from_listener)
26
+ }
27
+
28
+ @verify(lean, theorem = "doppler_air_default_freq_positive")
29
+ fn observed_frequency_air(f_source: Real,
30
+ v_listener_toward_source: Real,
31
+ v_source_away_from_listener: Real) -> Real
32
+ where chain_order <= 0
33
+ requires (f_source >= 0.0)
34
+ requires (V_SOUND_AIR + v_source_away_from_listener > 0.0)
35
+ ensures (result >= 0.0)
36
+ {
37
+ f_source * (V_SOUND_AIR + v_listener_toward_source)
38
+ / (V_SOUND_AIR + v_source_away_from_listener)
39
+ }
@@ -0,0 +1,32 @@
1
+ // lowpass_audio.eml -- first-order IIR low-pass for audio.
2
+ //
3
+ // y[n] = α * x[n] + (1 - α) * y[n-1]
4
+ //
5
+ // Where α = dt / (RC + dt) maps cutoff frequency to coefficient.
6
+ // Used for muffling audio behind walls, motion blur on sound,
7
+ // or simulating a chest-cavity filter on bullet impacts.
8
+
9
+ module lowpass_audio;
10
+
11
+ const TWO_PI: Real = 6.283185307179586
12
+
13
+ @verify(lean, theorem = "lowpass_alpha_in_unit_interval")
14
+ fn alpha_from_cutoff(cutoff_hz: Real, sample_rate_hz: Real) -> Real
15
+ where chain_order <= 0,
16
+ domain: cutoff_hz > 0.0 && sample_rate_hz > 0.0
17
+ ensures (result >= 0.0)
18
+ ensures (result <= 1.0)
19
+ {
20
+ let dt: Real = 1.0 / sample_rate_hz;
21
+ let rc: Real = 1.0 / (TWO_PI * cutoff_hz);
22
+ clamp(dt / (rc + dt), 0.0, 1.0)
23
+ }
24
+
25
+ @verify(lean, theorem = "lowpass_step_signed_bounded")
26
+ fn step(x_n: Real, y_prev: Real, alpha: Real) -> Real
27
+ where chain_order <= 0
28
+ requires (alpha >= 0.0)
29
+ requires (alpha <= 1.0)
30
+ {
31
+ alpha * x_n + (1.0 - alpha) * y_prev
32
+ }
@@ -0,0 +1,41 @@
1
+ // reverb_delay.eml -- single-tap delay line with feedback.
2
+ //
3
+ // y[n] = x[n] + feedback * y[n - delay_samples]
4
+ //
5
+ // Feedback ∈ [0, 1) so the recursive sum converges. Used as the
6
+ // elementary building block of comb-filter reverbs (chain N copies
7
+ // in parallel with prime-number delays for natural decay).
8
+
9
+ module reverb_delay;
10
+
11
+ @verify(lean, theorem = "reverb_feedback_in_open_unit_interval")
12
+ fn feedback_safe(coeff: Real) -> Real
13
+ where chain_order <= 0
14
+ requires (coeff >= 0.0)
15
+ requires (coeff < 1.0)
16
+ ensures (result >= 0.0)
17
+ ensures (result < 1.0)
18
+ {
19
+ clamp(coeff, 0.0, 0.999)
20
+ }
21
+
22
+ // One step of a feedback delay line.
23
+ @verify(lean, theorem = "delay_step_signed_bounded")
24
+ fn delay_step(x_n: Real, y_delayed: Real, feedback: Real) -> Real
25
+ where chain_order <= 0
26
+ requires (feedback >= 0.0)
27
+ requires (feedback < 1.0)
28
+ {
29
+ x_n + feedback * y_delayed
30
+ }
31
+
32
+ // Decay time for a feedback coefficient: T60 = 3 * delay_seconds / -log10(feedback)
33
+ @verify(lean, theorem = "reverb_t60_positive")
34
+ fn t60_seconds(delay_seconds: Real, feedback: Real) -> Real
35
+ where chain_order <= 1,
36
+ domain: delay_seconds > 0.0 && feedback > 0.0 && feedback < 1.0
37
+ ensures (result > 0.0)
38
+ {
39
+ let log_term: Real = -ln(feedback) / 2.302585093; // -log10(feedback)
40
+ 3.0 * delay_seconds / log_term
41
+ }
@@ -0,0 +1,30 @@
1
+ // dof_blur.eml -- depth-of-field circle of confusion.
2
+ //
3
+ // coc = aperture * |z_depth - z_focus| / z_depth
4
+ //
5
+ // `coc` is the circle of confusion radius in screen-space pixels;
6
+ // the post-process samples a disc of that radius around each
7
+ // fragment for the blur.
8
+
9
+ module dof_blur;
10
+
11
+ @verify(lean, theorem = "coc_nonneg")
12
+ fn circle_of_confusion(aperture: Real, z_depth: Real, z_focus: Real) -> Real
13
+ where chain_order <= 0,
14
+ domain: aperture >= 0.0 && z_depth > 0.0
15
+ ensures (result >= 0.0)
16
+ {
17
+ aperture * abs(z_depth - z_focus) / z_depth
18
+ }
19
+
20
+ // Clamp the COC to a maximum radius (texture sample budget).
21
+ @verify(lean, theorem = "coc_clamped_in_band")
22
+ fn circle_of_confusion_clamped(aperture: Real, z_depth: Real,
23
+ z_focus: Real, max_radius_px: Real) -> Real
24
+ where chain_order <= 0,
25
+ domain: aperture >= 0.0 && z_depth > 0.0 && max_radius_px >= 0.0
26
+ ensures (result >= 0.0)
27
+ ensures (result <= max_radius_px)
28
+ {
29
+ clamp(aperture * abs(z_depth - z_focus) / z_depth, 0.0, max_radius_px)
30
+ }
@@ -0,0 +1,47 @@
1
+ // fov_projection.eml -- perspective projection matrix coefficients.
2
+ //
3
+ // Returns the four non-zero entries of a standard right-handed
4
+ // perspective matrix (column-major):
5
+ //
6
+ // m00 = 1 / (aspect * tan(fov/2))
7
+ // m11 = 1 / tan(fov/2)
8
+ // m22 = -(far + near) / (far - near)
9
+ // m23 = -(2 * far * near) / (far - near)
10
+
11
+ module fov_projection;
12
+
13
+ @verify(lean, theorem = "fov_m00_positive")
14
+ fn m00(fov_y_rad: Real, aspect: Real) -> Real
15
+ where chain_order <= 2,
16
+ domain: fov_y_rad > 0.0 && fov_y_rad < 3.141 && aspect > 0.0
17
+ ensures (result > 0.0)
18
+ {
19
+ 1.0 / (aspect * tan(0.5 * fov_y_rad))
20
+ }
21
+
22
+ @verify(lean, theorem = "fov_m11_positive")
23
+ fn m11(fov_y_rad: Real) -> Real
24
+ where chain_order <= 2,
25
+ domain: fov_y_rad > 0.0 && fov_y_rad < 3.141
26
+ ensures (result > 0.0)
27
+ {
28
+ 1.0 / tan(0.5 * fov_y_rad)
29
+ }
30
+
31
+ @verify(lean, theorem = "fov_m22_signed")
32
+ fn m22(near: Real, far: Real) -> Real
33
+ where chain_order <= 0,
34
+ domain: near > 0.0 && far > near
35
+ ensures (result < 0.0)
36
+ {
37
+ -(far + near) / (far - near)
38
+ }
39
+
40
+ @verify(lean, theorem = "fov_m23_signed")
41
+ fn m23(near: Real, far: Real) -> Real
42
+ where chain_order <= 0,
43
+ domain: near > 0.0 && far > near
44
+ ensures (result < 0.0)
45
+ {
46
+ -(2.0 * far * near) / (far - near)
47
+ }
@@ -0,0 +1,48 @@
1
+ // orbit.eml -- spherical-coordinates orbit camera.
2
+ //
3
+ // x = r * cos(φ) * sin(θ)
4
+ // y = r * sin(φ)
5
+ // z = r * cos(φ) * cos(θ)
6
+ //
7
+ // θ = azimuth (around y-axis), φ = elevation (above XZ plane), r = radius.
8
+
9
+ module orbit;
10
+
11
+ @verify(lean, theorem = "orbit_x_in_band")
12
+ fn position_x(r: Real, theta_rad: Real, phi_rad: Real) -> Real
13
+ where chain_order <= 1,
14
+ domain: r >= 0.0
15
+ ensures (abs(result) <= r)
16
+ {
17
+ r * cos(phi_rad) * sin(theta_rad)
18
+ }
19
+
20
+ @verify(lean, theorem = "orbit_y_in_band")
21
+ fn position_y(r: Real, phi_rad: Real) -> Real
22
+ where chain_order <= 1,
23
+ domain: r >= 0.0
24
+ ensures (abs(result) <= r)
25
+ {
26
+ r * sin(phi_rad)
27
+ }
28
+
29
+ @verify(lean, theorem = "orbit_z_in_band")
30
+ fn position_z(r: Real, theta_rad: Real, phi_rad: Real) -> Real
31
+ where chain_order <= 1,
32
+ domain: r >= 0.0
33
+ ensures (abs(result) <= r)
34
+ {
35
+ r * cos(phi_rad) * cos(theta_rad)
36
+ }
37
+
38
+ // Pythagorean witness: x² + y² + z² = r²
39
+ @verify(lean, theorem = "orbit_norm_witness")
40
+ fn norm_witness(theta_rad: Real, phi_rad: Real) -> Real
41
+ where chain_order <= 1
42
+ ensures (result == 1.0)
43
+ {
44
+ let cx: Real = cos(phi_rad) * sin(theta_rad);
45
+ let sy: Real = sin(phi_rad);
46
+ let cz: Real = cos(phi_rad) * cos(theta_rad);
47
+ cx * cx + sy * sy + cz * cz
48
+ }
@@ -0,0 +1,20 @@
1
+ // shake.eml -- damped-noise camera shake.
2
+ //
3
+ // shake(t) = magnitude * exp(-decay * t) * perlin(t * frequency, 0)
4
+ //
5
+ // Returns a 1D scalar offset; caller threads this into x and y
6
+ // with two different time offsets to get a 2D displacement.
7
+
8
+ module shake;
9
+
10
+ use stdlib::gaming::noise::perlin_2d;
11
+
12
+ @verify(lean, theorem = "shake_magnitude_in_band")
13
+ fn shake1d(magnitude: Real, decay: Real, frequency: Real, t_s: Real) -> Real
14
+ where chain_order <= 1,
15
+ domain: decay >= 0.0 && frequency >= 0.0 && t_s >= 0.0
16
+ {
17
+ let envelope: Real = magnitude * exp(-decay * t_s);
18
+ let noise: Real = perlin_2d::perlin2(t_s * frequency, 0.0);
19
+ envelope * noise
20
+ }