Files
Toolbox/dev_test_scripts/unit/test_four_dim_polytopes.js
T
yangxiangyuan 4492b4106a feat: 新增3个思想实验室项目,完善私有剪贴板授权与上传功能,添加配套测试脚本
1. 新增怀旧弹珠台、人性与投资、穿越三体、四维空间四个思想实验室项目
2. 为私有剪贴板添加业务层授权校验,优化上传进度显示与鉴权失败处理
3. 新增多个调试与单元测试脚本,覆盖三体积分、弹珠台物理、集成测试等场景
4. 补全穿越三体项目的完整HTML页面资源
2026-08-07 17:49:24 +08:00

84 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// 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)