mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-19 12:58:04 +00:00
- Rename puzzle configuration files for consistency (e.g., InChI2logP_test.json) - Standardize class names to PascalCase (e.g., InChI2MRBootCamp -> InChI2MRbootCamp) - Improve code structure in various bootcamp modules for better readability and maintainability - Update import statements and file references to reflect new naming conventions - Enhance setup.py to include rdkit dependency
107 lines
No EOL
3.8 KiB
Python
107 lines
No EOL
3.8 KiB
Python
import re
|
||
import json
|
||
import numpy as np
|
||
from scipy.integrate import odeint
|
||
from internbootcamp.bootcamp.base import Basebootcamp
|
||
|
||
|
||
class LinearODEbootcamp(Basebootcamp):
|
||
def __init__(
|
||
self,
|
||
k_range=(0.1, 1.0),
|
||
x0_range=(0.5, 2.0),
|
||
t_span=(0, 5),
|
||
n_points=50,
|
||
seed=None
|
||
):
|
||
self.k_range, self.x0_range = k_range, x0_range
|
||
self.t0, self.t1 = t_span
|
||
self.n_points = n_points
|
||
if seed is not None:
|
||
np.random.seed(seed)
|
||
|
||
def case_generator(self):
|
||
# 1. 随机采样参数 k 和初始值 x0
|
||
k = float(np.random.uniform(*self.k_range))
|
||
x0 = float(np.random.uniform(*self.x0_range))
|
||
# 2. 构造时间序列并模拟 dx/dt = -k * x
|
||
t = np.linspace(self.t0, self.t1, self.n_points).tolist()
|
||
def model(x, t_val):
|
||
return -k * x
|
||
x = odeint(model, x0, t).flatten().tolist()
|
||
return {"t": t, "x": x, "k": k}
|
||
|
||
def prompt_func(self, identity) -> str:
|
||
# 将 (t, x) 对格式化为提示
|
||
points = ", ".join(f"({t:.2f}, {x:.2f})"
|
||
for t, x in zip(identity["t"], identity["x"]))
|
||
return (
|
||
f"下面给出变量 x(t) 的观测数据点:\n{points}\n\n"
|
||
"请找出其满足的微分方程,形式为:dx/dt = f(x)。\n"
|
||
"以dx/dt = <表达式>格式表示你的答案。"
|
||
"并且使用[answer]标签包裹你的最终答案, 例如[answer]dx/dt = <表达式>[/answer]."
|
||
)
|
||
|
||
@staticmethod
|
||
def extract_output(output):
|
||
import re
|
||
matches = re.findall(r'\[answer\](.*?)\[/answer\]', output, re.DOTALL)
|
||
if not matches:
|
||
return None
|
||
last_match = matches[-1].strip()
|
||
try:
|
||
raw_expr = last_match.replace('dx/dt = ', '').strip()
|
||
expr = raw_expr.strip()
|
||
pattern = re.fullmatch(
|
||
r"""
|
||
([+-]?\s* # 可选的正负号,后可带空格
|
||
(?:\d+(?:\.\d*)? # 整数或小数点后数字
|
||
|\.\d+)? # 或只有小数部分
|
||
(?:[eE][+-]?\d+)? # 可选的科学计数部分
|
||
)? # 整个系数是可选的(允许直接 x 或 -x)
|
||
\s*\*?\s* # 可选乘号,前后允许空格
|
||
[xX] # x 或 X
|
||
""",
|
||
expr,
|
||
re.VERBOSE
|
||
)
|
||
|
||
if pattern:
|
||
raw = pattern.group(1)
|
||
if raw is None or raw.strip() == '':
|
||
return 1.0
|
||
elif raw.strip() in ['+', '+1']:
|
||
return 1.0
|
||
elif raw.strip() in ['-', '-1']:
|
||
return -1.0
|
||
else:
|
||
return float(raw)
|
||
else:
|
||
return None
|
||
except ValueError:
|
||
return None
|
||
|
||
@classmethod
|
||
def _verify_correction(cls, solution: float, identity: dict) -> bool:
|
||
delta = abs(solution + identity["k"])
|
||
return delta < 1e-2
|
||
|
||
|
||
if __name__ == "__main__":
|
||
bootcamp = LinearODEbootcamp(seed=123)
|
||
# 生成几个样例
|
||
examples = [bootcamp.case_generator() for _ in range(3)]
|
||
|
||
for identity in examples:
|
||
# 构造“模型”返回答案,模拟 LLM 的输出
|
||
coeff = -identity["k"]
|
||
sol = f"[answer]dx/dt = {coeff:.2f}*x[/answer]"
|
||
# 调用 Basebootcamp 提供的 verify_score 接口进行验证
|
||
score = bootcamp.verify_score(sol, identity, short_penalty=False,format_penalty=False)
|
||
# 打印结果
|
||
print(json.dumps({
|
||
"identity": identity,
|
||
"solution": sol,
|
||
"extract_output": LinearODEbootcamp.extract_output(sol),
|
||
"verify_score": score
|
||
}, ensure_ascii=False, indent=2)) |