跳转到内容

同形不同意图实验源码

研究总览 · 2026-09-20

附录 F:表示和修改语义的隔离实验。

附录 F:同形不同意图的表示再求值实验

Section titled “附录 F:同形不同意图的表示再求值实验”

对应 §17.7。将下列完整源码保存为 TEMP 中的 aira-intent-representation-probe-20260920.mjs,使用 Node 运行。当前源文件 SHA-256 为 e6ce700fa8b6078776b736ce7d38aa427492813c010b406c8fcf8a7fc96d3f45。工作区路径按本机调整;HiGHS 使用附录 C 的同一隔离构件,不添加产品依赖。

实际环境为 Node 24.19.0、Windows x64、i7-13700F,HiGHS 报告核心 1.15.1 / 04024d7。OCCT WASM SHA-256 为 218e80a3fb69d62de4b44b613f64c0d99f3f8d2ad5cb5ce3aeea568805fcdcfa;HiGHS JS SHA-256 为 0bd23843c9795753f2276e9901eb2a1e66288547b6bcba84fa0665dc037b5c7c。脚本将完整输入、各候选结果、B-Rep 检查、状态及构件哈希写到 TEMP 的同名 JSON。summary.variables 仅指显式 LP 变量数,correct-reject 不代表已完成产品回滚或不可行证书核验;不可行单元没有构造几何。

这是有限构造域的隔离机制探针,不是产品执行器或 test/spec 套件。所有配方由研究者编写并携带相同政策逐输入再求值;没有模型持久化、真实编辑链和 AI 试用。诊断时长包含各自实际调用成本,但单格一次,不能用于方案性能排名。

import fs from 'node:fs';
import os from 'node:os';
import crypto from 'node:crypto';
import { createRequire } from 'node:module';
import { pathToFileURL } from 'node:url';
const require = createRequire(import.meta.url);
const root = '<workspace-root>';
const runtime = root + '/packages/aira-geometry-kernel/runtime/feature-graph/aira_occt_feature_graph';
const highPath = os.tmpdir() + '/aira-highs-standalone-research-20260920/highs.js';
const hash = x => crypto.createHash('sha256').update(x).digest('hex');
const t0 = performance.now();
const { default: init } = await import(pathToFileURL(runtime + '.js'));
const wasmBinary = fs.readFileSync(runtime + '.wasm');
const oc = await init({ wasmBinary });
const occtLoaded = performance.now();
const high = await require(highPath)();
const loaded = performance.now();
const eps = 1e-7;
const constants = { height: 30, thickness: 4, radius: 3, n: 4, edge: 7, web: 3, pitch: 20 };
// Feature recipes retain seed/pitch expressions, not just sampled coordinates.
const featureRecipes = {
edge: { origin: p => p.radius + p.edge, pitch: p => (p.width - 2 * (p.radius + p.edge)) / (p.n - 1) },
pitch: { origin: p => (p.width - (p.n - 1) * p.pitch) / 2, pitch: p => p.pitch },
};
function feature(p, intent) {
const recipe = featureRecipes[intent], start = recipe.origin(p), step = recipe.pitch(p);
return { x: Array.from({ length: p.n }, (_, i) => start + i * step) };
}
function program(p, intent) {
const x = [];
for (let i = 0; i < p.n; i++) x.push(intent === 'edge'
? p.radius + p.edge + i * (p.width - 2 * (p.radius + p.edge)) / (p.n - 1)
: p.width / 2 + (i - (p.n - 1) / 2) * p.pitch);
return { x };
}
function lp(n, rows) {
const columns = Array.from({ length: n }, () => []);
rows.forEach((r, i) => r.a.forEach(([j, a]) => columns[j].push([i, a])));
const starts = [], indices = [], values = [];
for (const col of columns) {
starts.push(indices.length);
for (const [i, a] of col) { indices.push(i); values.push(a); }
}
starts.push(indices.length);
const model = high.createModel({ numCols: n, numRows: rows.length,
colCost: Array(n).fill(0), colLower: Array(n).fill(-high.infinity), colUpper: Array(n).fill(high.infinity),
rowLower: rows.map(r => r.lo ?? -high.infinity), rowUpper: rows.map(r => r.hi ?? high.infinity),
matrix: { format: 'csc', numRows: rows.length, numCols: n, starts, indices, values } });
try {
model.options.set({ output_flag: false, solver: 'simplex' });
const status = model.run().modelStatus;
if (status === 7) return { values: Array.from(model.getSolution().colValue), status, variables: n, constraints: rows.length };
return { status, variables: n, constraints: rows.length };
} finally { model.dispose(); }
}
function relation(p, intent) {
const rows = [], last = p.n - 1, eq = (a, b) => rows.push({ a, lo: b, hi: b });
for (let i = 0; i < p.n; i++) rows.push({ a: [[i, 1]], lo: p.radius + p.edge, hi: p.width - p.radius - p.edge });
for (let i = 0; i < last; i++) rows.push({ a: [[i + 1, 1], [i, -1]], lo: 2 * p.radius + p.web });
if (intent === 'edge') {
eq([[0, 1]], p.radius + p.edge); eq([[last, 1]], p.width - p.radius - p.edge);
for (let i = 1; i < last; i++) eq([[i - 1, 1], [i, -2], [i + 1, 1]], 0);
} else {
for (let i = 0; i < last; i++) eq([[i + 1, 1], [i, -1]], p.pitch);
eq([[0, 1], [last, 1]], p.width);
}
const r = lp(p.n, rows); return { ...r, x: r.values };
}
function hybrid(p, intent) {
// Solve seed s and pitch q, then use the same procedural pattern x_i=s+i*q.
const rows = [{ a: [[0, 1]], lo: p.radius + p.edge },
{ a: [[0, 1], [1, p.n - 1]], hi: p.width - p.radius - p.edge },
{ a: [[1, 1]], lo: 2 * p.radius + p.web }];
const eq = (a, b) => rows.push({ a, lo: b, hi: b });
if (intent === 'edge') {
eq([[0, 1]], p.radius + p.edge); eq([[0, 1], [1, p.n - 1]], p.width - p.radius - p.edge);
} else { eq([[1, 1]], p.pitch); eq([[0, 2], [1, p.n - 1]], p.width); }
const r = lp(2, rows);
return { ...r, x: r.values && Array.from({ length: p.n }, (_, i) => r.values[0] + i * r.values[1]) };
}
function requirements(p, intent, xs) {
if (!xs || xs.length !== p.n || xs.some(x => !Number.isFinite(x))) return { pass: false, reason: 'missing-or-invalid-centres' };
const x = [...xs].sort((a, b) => a - b), gaps = x.slice(1).map((v, i) => v - x[i]);
const margins = [x[0] - p.radius, p.width - x.at(-1) - p.radius];
const equalPitch = Math.max(...gaps) - Math.min(...gaps) <= eps;
const inDomain = Math.min(...margins) >= p.edge - eps && Math.min(...gaps) >= 2 * p.radius + p.web - eps;
const intentOK = intent === 'edge' ? margins.every(m => Math.abs(m - p.edge) <= eps)
: gaps.every(g => Math.abs(g - p.pitch) <= eps) && Math.abs(x[0] + x.at(-1) - p.width) <= eps;
return { pass: equalPitch && inDomain && intentOK, equalPitch, inDomain, intentOK, margins, gaps };
}
function scope(fn) {
const held = [], take = x => (held.push(x), x);
try { return fn(take); } finally { for (const x of held.reverse()) x.delete(); }
}
function build(p, xs) {
return scope(h => {
const point = (x, y, z) => h(new oc.gp_Pnt(x, y, z));
const polygon = h(new oc.BRepBuilderAPI_MakePolygon());
for (const [x, y] of [[0, 0], [p.width, 0], [p.width, p.height], [0, p.height]]) polygon.Add(point(x, y, 0));
polygon.Close(); const face = h(new oc.BRepBuilderAPI_MakeFace(h(polygon.Wire()), false));
for (const x of xs) {
const axis = h(new oc.gp_Ax2(point(x, p.height / 2, 0), h(new oc.gp_Dir(0, 0, 1))));
const circle = h(new oc.gp_Circ(axis, p.radius));
const edge = h(new oc.BRepBuilderAPI_MakeEdge(circle));
const wireMaker = h(new oc.BRepBuilderAPI_MakeWire(h(edge.Edge())));
const wire = h(wireMaker.Wire()); wire.Reverse(); face.Add(wire);
}
if (!face.IsDone()) throw Error('face construction failed');
const prism = h(new oc.BRepPrimAPI_MakePrism(h(face.Face()), h(new oc.gp_Vec(0, 0, p.thickness)), false, true));
if (!prism.IsDone()) throw Error('prism construction failed');
return prism.Shape();
});
}
function inspect(shape, p, intent) {
return scope(h => {
const analyzer = h(new oc.BRepCheck_Analyzer(shape, true, false, true));
const props = h(new oc.GProp_GProps()); oc.BRepGProp.VolumeProperties(shape, props, true, false, false);
const bounds = h(new oc.Bnd_Box()); oc.BRepBndLib.AddOptimal(shape, bounds, false, false);
const collect = type => {
const e = h(new oc.TopExp_Explorer(shape, type, oc.TopAbs_ShapeEnum.TopAbs_SHAPE)), items = [];
while (e.More()) { const item = h(e.Current()); if (!items.some(x => x.IsSame(item))) items.push(item); e.Next(); }
return items;
};
const solids = collect(oc.TopAbs_ShapeEnum.TopAbs_SOLID).length, cylinders = [];
for (const item of collect(oc.TopAbs_ShapeEnum.TopAbs_FACE)) {
const a = h(new oc.BRepAdaptor_Surface(h(oc.TopoDS.Face(item)), true));
if (a.GetType() !== oc.GeomAbs_SurfaceType.GeomAbs_Cylinder) continue;
const cyl = h(a.Cylinder()), loc = h(cyl.Location()), axis = h(cyl.Axis()), dir = h(axis.Direction());
cylinders.push({ x: loc.X(), y: loc.Y(), radius: cyl.Radius(), axisZ: dir.Z(),
u: a.LastUParameter() - a.FirstUParameter(), v: a.LastVParameter() - a.FirstVParameter() });
}
cylinders.sort((a, b) => a.x - b.x);
const boundsVector = [bounds.GetXMin(), bounds.GetYMin(), bounds.GetZMin(), bounds.GetXMax(), bounds.GetYMax(), bounds.GetZMax()];
const expectedBounds = [0, 0, 0, p.width, p.height, p.thickness];
const volume = props.Mass(), expectedVolume = (p.width * p.height - p.n * Math.PI * p.radius ** 2) * p.thickness;
const geometry = analyzer.IsValid() && solids === 1 && Math.abs(volume - expectedVolume) < eps
&& boundsVector.every((x, i) => Math.abs(x - expectedBounds[i]) < eps)
&& cylinders.length === p.n && cylinders.every(c => Math.abs(c.radius - p.radius) < eps
&& Math.abs(c.y - p.height / 2) < eps && Math.abs(Math.abs(c.axisZ) - 1) < eps
&& Math.abs(c.u - 2 * Math.PI) < eps && Math.abs(c.v - p.thickness) < eps);
return { geometry, intent: requirements(p, intent, cylinders.map(c => c.x)), cylinders, volume, expectedVolume, boundsVector, solids };
});
}
const methods = { feature, program, relation, hybrid }, rows = [];
const inputs = ['edge', 'pitch'].flatMap(intent => [80, 100, 60, 47, 46].map(width => ({ intent, width })));
for (const input of inputs) {
const p = { ...constants, width: input.width };
const necessaryWidth = input.intent === 'edge' ? 2 * (p.edge + p.radius) + (p.n - 1) * (2 * p.radius + p.web)
: 2 * (p.edge + p.radius) + (p.n - 1) * p.pitch;
const expectedFeasible = p.width >= necessaryWidth;
for (const [method, predict] of Object.entries(methods)) {
const start = performance.now(), result = predict(p, input.intent), predicted = performance.now();
const checked = requirements(p, input.intent, result.x); let measured;
if (checked.pass) { const shape = build(p, result.x); try { measured = inspect(shape, p, input.intent); } finally { shape.delete(); } }
const observedFeasible = Boolean(measured?.geometry && measured.intent.pass);
const outcome = expectedFeasible ? observedFeasible ? 'pass' : 'fail'
: !checked.pass && (method === 'feature' || method === 'program' || result.status === 8) ? 'correct-reject' : 'fail';
rows.push({ ...input, method, expectedFeasible, necessaryWidth, outcome, result, checked, measured,
predictionMs: predicted - start, totalMs: performance.now() - start });
}
}
// Negative control: geometry only, identical stored initial coordinates for both intents.
const negative = ['edge', 'pitch'].map(intent => {
const p = { ...constants, width: 100 }, x = [10, 30, 50, 70], shape = build(p, x);
try { return { intent, x, measured: inspect(shape, p, intent) }; } finally { shape.delete(); }
});
const summary = Object.fromEntries(Object.keys(methods).map(method => {
const r = rows.filter(x => x.method === method);
return [method, { pass: r.filter(x => x.outcome === 'pass').length, correctReject: r.filter(x => x.outcome === 'correct-reject').length,
fail: r.filter(x => x.outcome === 'fail').length, variables: method === 'relation' ? 4 : method === 'hybrid' ? 2 : 0 }];
}));
const report = { kind: 'isolated-intent-representation-mechanism-probe', timestamp: new Date().toISOString(), node: process.version,
platform: process.platform, cpu: os.cpus()[0].model, constants, tolerance: eps,
environment: { root, runtime, highPath, highVersion: high.version, wasmSha256: hash(wasmBinary),
occtJsSha256: hash(fs.readFileSync(runtime + '.js')), highJsSha256: hash(fs.readFileSync(highPath)),
scriptSha256: hash(fs.readFileSync(new URL(import.meta.url))), initializationMs: { occt: occtLoaded - t0, highs: loaded - occtLoaded } },
protocol: 'Author-written recipes; fixed 10 inputs per candidate, no independent holdout; prediction time includes construction of LP and disposal; common OCCT geometry and independent requirement checks; no AI authoring or native product transactions; timings diagnostic only, one sample per cell; not an AI success-rate or performance benchmark.',
summary, rows, negative };
const output = os.tmpdir() + '/aira-intent-representation-probe-20260920.json';
fs.writeFileSync(output, JSON.stringify(report, null, 2));
console.log(JSON.stringify({ output, summary, negative: negative.map(r => ({ intent: r.intent, geometry: r.measured.geometry, intentPass: r.measured.intent.pass })),
at100: rows.filter(r => r.width === 100).map(r => ({ method: r.method, intent: r.intent, x: r.result.x, outcome: r.outcome })) }, null, 2));
if (rows.some(r => r.outcome === 'fail') || negative.some(r => !r.measured.geometry || r.measured.intent.pass)) process.exitCode = 1;