| 326 | function runSymPy(): Record<string, any> { |
| 327 | const tasks = cases.map((c) => ({ id: c.id, op: c.op, expr: c.sympyExpr, expr2: c.sympyExpr2 ?? null, var: c.varName, points: POINTS, point: c.point ?? null, a: c.a ?? null, b: c.b ?? null })); |
| 328 | const tmp = join(mkdtempSync(join(tmpdir(), 'wester-')), 'tasks.json'); |
| 329 | writeFileSync(tmp, JSON.stringify(tasks)); |
| 330 | const by: Record<string, any> = {}; |
| 331 | try { |
| 332 | const out = execFileSync(PYTHON, [join(__dirname, 'run_sympy_wester.py'), tmp], { encoding: 'utf8', timeout: 900000 }); |
| 333 | for (const line of out.trim().split('\n')) { try { const o = JSON.parse(line); if (o.id) by[o.id] = o; } catch {} } |
| 334 | } catch (e: any) { console.error('sympy failed:', (e.message || e).toString().split('\n')[0]); } |
| 335 | return by; |
| 336 | } |
| 337 | |
| 338 | // --- Wolfram / Mathematica (batch) ----------------------------------------- |
| 339 | // The Wester files are *already* Mathematica, so Wolfram is the natural |
| 340 | // reference baseline here. We translate the same parsed `arg` MathJSON the other |
| 341 | // configs run (not the raw statement) into Wolfram Language and grade it with the |
| 342 | // identical invariant logic. `real: true` mirrors run_sympy_wester.py's |
| 343 | // `symbols(var, real=True)`. |
| 344 | const wlPoint = (p: any) => |
| 345 | p === 'PositiveInfinity' ? 'Infinity' : p === 'NegativeInfinity' ? '-Infinity' : String(p); |
| 346 | |
| 347 | function runWolfram(): Record<string, any> { |
| 348 | const by: Record<string, any> = {}; |
| 349 | const tasks: any[] = []; |
| 350 | for (const c of cases) { |
| 351 | try { |
| 352 | const t: any = { id: c.id, op: c.op, expr: mathJsonToWL(c.arg), var: c.varName, points: POINTS }; |
| 353 | if (c.arg2 !== undefined) t.expr2 = mathJsonToWL(c.arg2); |
| 354 | if (c.point !== undefined && c.point !== null) t.point = wlPoint(c.point); |