Spaces:
Running on Zero
Running on Zero
| #!/usr/bin/env python3 | |
| """Base STEM and Mathematical Reasoning replay dataset generator. | |
| Prevents catastrophic forgetting by mixing in step-by-step Chain of Thought (CoT) | |
| linear algebra, calculus, ODE, Laplace transforms, and physical systems reasoning. | |
| """ | |
| from __future__ import annotations | |
| import math | |
| import sys | |
| from pathlib import Path | |
| import numpy as np | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| if str(PROJECT_ROOT) not in sys.path: | |
| sys.path.insert(0, str(PROJECT_ROOT)) | |
| from controlai_data.schema import make_record | |
| def n(val: float) -> str: | |
| if abs(val) < 1e-12: | |
| return "0.0" | |
| return f"{val:.6g}" | |
| def mat_str(arr: np.ndarray) -> str: | |
| return repr(np.asarray(arr, dtype=float).tolist()) | |
| def generate_laplace_partial_fractions(count: int, seed: int) -> list[dict]: | |
| """Generate partial fraction expansion of rational transfer functions with step-by-step math.""" | |
| records = [] | |
| for i in range(count): | |
| p1 = -(1.0 + 0.5 * (i % 4)) | |
| p2 = -(3.0 + 0.5 * (i % 5)) | |
| z = 2.0 + 0.25 * (i % 3) | |
| # F(s) = (s + z) / ((s - p1)(s - p2)) = A / (s - p1) + B / (s - p2) | |
| # A = (p1 + z) / (p1 - p2) | |
| # B = (p2 + z) / (p2 - p1) | |
| A_res = (p1 + z) / (p1 - p2) | |
| B_res = (p2 + z) / (p2 - p1) | |
| prompt = ( | |
| f"Compute the inverse Laplace transform $f(t) = \\mathcal{{L}}^{{-1}}\\{{F(s)\\}}$ for $t \\ge 0$, where " | |
| f"$$F(s) = \\frac{{s + {n(z)}}}{{(s + {n(-p1)})(s + {n(-p2)})}}$$. " | |
| f"Show the step-by-step partial fraction expansion and state the time-domain signal." | |
| ) | |
| answer = ( | |
| f"### 1. Partial Fraction Decomposition\n" | |
| f"Write $F(s)$ in terms of first-order partial fractions with distinct poles $s_1 = {n(p1)}$ and $s_2 = {n(p2)}$:\n" | |
| f"$$F(s) = \\frac{{s + {n(z)}}}{{(s - ({n(p1)}))(s - ({n(p2)}))}} = \\frac{{C_1}}{{s - ({n(p1)})}} + \\frac{{C_2}}{{s - ({n(p2)})}}$$\n\n" | |
| f"### 2. Residue Calculation\n" | |
| f"Applying the residue formula:\n" | |
| f"$$C_1 = \\lim_{{s \\to {n(p1)}}} (s - ({n(p1)})) F(s) = \\frac{{{n(p1)} + {n(z)}}}{{{n(p1)} - ({n(p2)})}} = \\frac{{{n(p1 + z)}}}{{{n(p1 - p2)}}} = {n(A_res)}$$\n" | |
| f"$$C_2 = \\lim_{{s \\to {n(p2)}}} (s - ({n(p2)})) F(s) = \\frac{{{n(p2)} + {n(z)}}}{{{n(p2)} - ({n(p1)})}} = \\frac{{{n(p2 + z)}}}{{{n(p2 - p1)}}} = {n(B_res)}$$\n\n" | |
| f"Thus, the expanded expression is:\n" | |
| f"$$F(s) = \\frac{{{n(A_res)}}}{{s + {n(-p1)}}} + \\frac{{{n(B_res)}}}{{s + {n(-p2)}}}$$\n\n" | |
| f"### 3. Inverse Laplace Transform\n" | |
| f"Using the standard pair $\\mathcal{{L}}^{{-1}}\\{{\\frac{{1}}{{s + a}}\\}} = e^{{-at}} u(t)$:\n" | |
| f"$$f(t) = ({n(A_res)} e^{{{n(p1)} t}} + {n(B_res)} e^{{{n(p2)} t}}) u(t)$$\n" | |
| f"**Conclusion:** The causal time-domain signal is $f(t) = {n(A_res)} e^{{{n(p1)} t}} + {n(B_res)} e^{{{n(p2)} t}}$ for $t \\ge 0$." | |
| ) | |
| record = make_record( | |
| record_id=f"stem_laplace_partial_fraction_{i:04d}", | |
| domain="classical_optimal_control", | |
| family="stem_laplace_partial_fraction", | |
| task_type="derivation", | |
| difficulty="foundation", | |
| template_id=f"laplace_partial_fraction_prompt_{i % 4}", | |
| prompt=prompt, | |
| answer=answer, | |
| ground_truth={ | |
| "kind": "laplace_inversion", | |
| "p1": p1, | |
| "p2": p2, | |
| "z": z, | |
| "C1": A_res, | |
| "C2": B_res, | |
| }, | |
| source_refs=["stanford_ee263_course_reader", "astrom_murray_feedback_systems_1e"], | |
| verifier="verify_laplace_inversion", | |
| tool="requirements_analysis", | |
| ) | |
| records.append(record) | |
| return records | |
| def generate_rlc_circuit_cases(count: int, seed: int) -> list[dict]: | |
| """Generate series RLC circuit frequency response & damping ratio analysis.""" | |
| records = [] | |
| for i in range(count): | |
| R = 10.0 + 2.0 * (i % 5) # Ohms | |
| L = 0.05 + 0.01 * (i % 4) # Henry | |
| C = 0.001 + 0.0002 * (i % 3) # Farad | |
| # Series RLC: L * ddot(q) + R * dot(q) + (1/C)*q = v(t) | |
| # Characteristic eq: s^2 + (R/L)s + 1/(LC) = s^2 + 2*zeta*wn*s + wn^2 | |
| wn = 1.0 / math.sqrt(L * C) | |
| zeta = R / (2.0 * math.sqrt(L / C)) | |
| wd = wn * math.sqrt(abs(1.0 - zeta**2)) if zeta < 1.0 else 0.0 | |
| if zeta < 1.0: | |
| regime = "underdamped" | |
| elif abs(zeta - 1.0) < 1e-4: | |
| regime = "critically damped" | |
| else: | |
| regime = "overdamped" | |
| prompt = ( | |
| f"Analyze a series RLC circuit with resistor $R = {n(R)}$ $\\Omega$, inductor $L = {n(L)}$ H, " | |
| f"and capacitor $C = {n(C)}$ F. " | |
| f"Find the natural frequency $\\omega_n$, damping ratio $\\zeta$, damped natural frequency $\\omega_d$, " | |
| f"and characterize the transient response regime." | |
| ) | |
| answer = ( | |
| f"### 1. Differential Equation and Standard Form\n" | |
| f"Applying Kirchhoff's Voltage Law (KVL) around the series loop with charge $q(t)$:\n" | |
| f"$$L \\frac{{d^2q}}{{dt^2}} + R \\frac{{dq}}{{dt}} + \\frac{{1}}{{C}} q = v(t)$$\n\n" | |
| f"Dividing by $L$ puts the equation into canonical second-order form $\\ddot{{q}} + 2\\zeta \\omega_n \\dot{{q}} + \\omega_n^2 q = \\frac{{1}}{{L}} v(t)$:\n" | |
| f"$$\\ddot{{q}} + \\frac{{{n(R)}}}{{{n(L)}}} \\dot{{q}} + \\frac{{1}}{{{n(L)} \\times {n(C)}}} q = \\frac{{1}}{{{n(L)}}} v(t)$$\n\n" | |
| f"### 2. Parameter Extraction\n" | |
| f"1. **Natural frequency $\\omega_n$**:\n" | |
| f"$$\\omega_n = \\frac{{1}}{{\\sqrt{{LC}}}} = \\frac{{1}}{{\\sqrt{{{n(L)} \\times {n(C)}}}}} = {n(wn)}\\text{{ rad/s}}$$\n\n" | |
| f"2. **Damping ratio $\\zeta$**:\n" | |
| f"$$2\\zeta \\omega_n = \\frac{{R}}{{L}} \\implies \\zeta = \\frac{{R}}{{2 \\sqrt{{L/C}}}} = \\frac{{{n(R)}}}{{2 \\sqrt{{{n(L)} / {n(C)}}}}} = {n(zeta)}$$\n\n" | |
| f"3. **Damped frequency $\\omega_d$**:\n" | |
| f"$$\\omega_d = \\omega_n \\sqrt{{|1 - \\zeta^2|}} = {n(wd)}\\text{{ rad/s}}$$\n\n" | |
| f"### 3. Conclusion\n" | |
| f"Since $\\zeta = {n(zeta)}$ ({'< 1' if zeta < 1.0 else '> 1'}), the system is **{regime}**." | |
| ) | |
| record = make_record( | |
| record_id=f"stem_rlc_circuit_{i:04d}", | |
| domain="classical_optimal_control", | |
| family="stem_rlc_circuit_transient", | |
| task_type="numerical", | |
| difficulty="foundation", | |
| template_id=f"rlc_circuit_prompt_{i % 4}", | |
| prompt=prompt, | |
| answer=answer, | |
| ground_truth={ | |
| "kind": "second_order_transient", | |
| "R": R, | |
| "L": L, | |
| "C": C, | |
| "wn": wn, | |
| "zeta": zeta, | |
| "wd": wd, | |
| "regime": regime, | |
| }, | |
| source_refs=["stanford_ee263_course_reader", "astrom_murray_feedback_systems_1e"], | |
| verifier="verify_second_order_transient", | |
| tool="requirements_analysis", | |
| ) | |
| records.append(record) | |
| return records | |
| def build_all_stem_records(count_per_case: int = 50, seed: int = 20260902) -> list[dict]: | |
| """Compile all STEM replay records.""" | |
| records = [] | |
| records.extend(generate_laplace_partial_fractions(count_per_case, seed)) | |
| records.extend(generate_rlc_circuit_cases(count_per_case, seed + 1000)) | |
| return records | |
| if __name__ == "__main__": | |
| cases = build_all_stem_records(40) | |
| print(f"Generated {len(cases)} STEM replay SFT records.") | |