// ============================================================ // test_four_dim_polytopes.js - 四维空间实验室数学块校验 // 从 public/tools/thought_lab/labs/four_dim_space/index.html 抽取 // POLYTOPE_MATH_BEGIN/END 之间的纯数学代码执行校验,保证测试对象 = 上线代码。 // 校验:5 个凸正多胞体的顶点数/边数(严格已知值)、外接半径全等、 // 旋转保范、投影 w=0 时缩放为 1、偶排列数 = 12。 // 运行:node dev_test_scripts/unit/test_four_dim_polytopes.js // ============================================================ 'use strict' const fs = require('fs') const path = require('path') const vm = require('vm') const HTML = path.resolve(__dirname, '..', '..', 'public', 'tools', 'thought_lab', 'labs', 'four_dim_space', 'index.html') const src = fs.readFileSync(HTML, 'utf8') const m = src.match(/\/\/ ==== POLYTOPE_MATH_BEGIN ====\n([\s\S]*?)\/\/ ==== POLYTOPE_MATH_END ====/) if (!m) { console.error('FAIL - 未找到 POLYTOPE_MATH 标记块'); process.exit(1) } const api = vm.runInNewContext(m[1] + ` ;({ POLYTOPES, edgesByMinDist, rotate4, project4to3, project3to2, evenPerms4, perms4, PHI }) `) let pass = 0, fail = 0 const check = (name, cond) => { if (cond) { pass++; console.log('PASS -', name) } else { fail++; console.log('FAIL -', name) } } const norm = v => Math.sqrt(v.reduce((s, x) => s + x * x, 0)) // 排列数 check('4 元素全排列 = 24', api.perms4.length === 24) check('偶排列 = 12', api.evenPerms4.length === 12) // 各多胞体:顶点数 / 边数 / 外接半径全等 for (const key of Object.keys(api.POLYTOPES)) { const P = api.POLYTOPES[key] const verts = P.verts() const edges = api.edgesByMinDist(verts) check(`${key} 顶点数 = ${P.expect.v}`, verts.length === P.expect.v) check(`${key} 边数 = ${P.expect.e}`, edges.length === P.expect.e) const rs = verts.map(norm) const rMin = Math.min(...rs), rMax = Math.max(...rs) check(`${key} 外接半径全等(${rMin.toFixed(6)})`, rMax - rMin < 1e-9) } // 600-胞体最小边长应 = 1/φ(单位外接半径) { const verts = api.POLYTOPES.p600.verts() let min = Infinity for (let i = 0; i < verts.length; i++) for (let j = i + 1; j < verts.length; j++) { let s = 0 for (let k = 0; k < 4; k++) { const d = verts[i][k] - verts[j][k]; s += d * d } min = Math.min(min, s) } check('600-胞体边长 = 1/φ', Math.abs(Math.sqrt(min) - 1 / api.PHI) < 1e-9) } // 旋转保范:六个平面各转 0.7 rad { const v = [1, 2, 3, 4] const planes = [[0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3]] let ok = true for (const [i, j] of planes) { const q = api.rotate4(v, i, j, 0.7) if (Math.abs(norm(q) - norm(v)) > 1e-12) ok = false } check('六平面旋转均保范', ok) } // 投影:w=0 时 4D→3D 缩放为 1;w>0 放大 { const a = api.project4to3([1, 1, 1, 0], 3) const b = api.project4to3([1, 1, 1, 0.9], 3) check('project4to3 w=0 缩放=1', Math.abs(a[0] - 1) < 1e-12) check('project4to3 w>0 放大', b[0] > 1) const c = api.project3to2([1, 1, 0], 6) check('project3to2 z=0 缩放=1', Math.abs(c[0] - 1) < 1e-12) } console.log(fail === 0 ? `ALL PASS (${pass})` : `FAILED: ${fail} / ${pass + fail}`) process.exit(fail === 0 ? 0 : 1)