数学降阶与几何构造实验源码
研究总览 · 2026-09-20
附录 D:解析判定、消元和实际几何对照的复现材料。
附录 D:数学表示与实际几何构造的完整探针
Section titled “附录 D:数学表示与实际几何构造的完整探针”所有探针仅在 TEMP 运行;不是产品执行器,不进入测试框架。HiGHS 使用附录 C 相同的独立构件目录,CasADi/OCCT 使用当前项目锁定构件。复现时将对应源码保存为所列文件名,按实际工作区调整明确的 ROOT/runtime 路径;不要修改产品加载器。脚本路径日期是记录标识,D.4 的 20260921 是独立 seed/文件名,实验仍在本研究日期完成。
D.1 中使用 JavaScript BigInt 的小型有理数核验只服务于隔离实验;产品选择仍为已有 num-rational/num-bigint,不将此探针升级为第二套算术库。微实验输出和原始样本留在 TEMP,本组研究保存输入生成、完整算法、环境、观测汇总及源码哈希;不另建平行结论或产品执行器。
D.1 对称孔位的展开、降维与精确判定
Section titled “D.1 对称孔位的展开、降维与精确判定”文件:aira-323-feasibility-research-20260920.cjs。SHA-256:25d89b6cc2b23036bb70922bbac2a2bebc7df55f5ebb59afaa37663a817c9a43。
运行:node aira-323-feasibility-research-20260920.cjs > aira-323-feasibility-research-20260920.json 2> aira-323-feasibility-research-20260920.stderr.log。
完整复现源码
const fs=require('node:fs'),path=require('node:path'),os=require('node:os');const ROOT='<workspace-root>/packages/aira-geometry-kernel/node_modules/@casadi/casadi-wasm';const stats=a=>{a=[...a].sort((x,y)=>x-y);return {n:a.length,p50_ms:a[Math.floor(a.length/2)],p95_ms:a[Math.ceil(a.length*.95)-1],min_ms:a[0],max_ms:a.at(-1)}};const gcd=(a,b)=>{a=a<0n?-a:a;while(b){const r=a%b;a=b;b=r}return a};const rat=(n,d=1n)=>{if(d<0n){n=-n;d=-d}const g=gcd(n,d);return {n:n/g,d:d/g}};const add=(a,b)=>rat(a.n*b.d+b.n*a.d,a.d*b.d),neg=a=>({n:-a.n,d:a.d}),sub=(a,b)=>add(a,neg(b)),mul=(a,b)=>rat(a.n*b.n,a.d*b.d),cmp=(a,b)=>{const r=a.n*b.d-b.n*a.d;return r<0n?-1:r>0n?1:0};const half=a=>rat(a.n,a.d*2n),sq=a=>mul(a,a),ONE=rat(1n),ZERO=rat(0n),HALF=rat(1n,2n);function decimal(s){let sign=1n;if(s.startsWith('-')){sign=-1n;s=s.slice(1)}const a=s.split('.');return rat(sign*BigInt(a.join('')),10n**BigInt(a[1]?.length??0))}function binary(x){if(!Number.isFinite(x))throw new Error('nonfinite candidate');if(x===0)return ZERO;const d=new DataView(new ArrayBuffer(8));d.setFloat64(0,x,false);const v=d.getBigUint64(0,false),sign=(v>>63n)?-1n:1n,e=Number((v>>52n)&2047n),f=v&((1n<<52n)-1n);let n=sign*(e?f+(1n<<52n):f),k=(e?e-1023:-1022)-52;return k>=0?rat(n<<BigInt(k)):rat(n,1n<<BigInt(-k))}function geometry(p,h){return [[neg(p),h],[ZERO,h],[p,h],[neg(half(p)),ZERO],[half(p),ZERO],[neg(p),neg(h)],[ZERO,neg(h)],[p,neg(h)]]}function numericGeometry(p,h){return [[-p,h],[0,h],[p,h],[-p/2,0],[p/2,0],[-p,-h],[0,-h],[p,-h]]}function closed(P,T){return cmp(P,ONE)>=0&&cmp(T,HALF)>=0&&cmp(add(sq(half(P)),sq(T)),ONE)>=0}function verify(p,h,P,T){if(!Number.isFinite(p)||!Number.isFinite(h))return {pass:false,reason:'nonfinite'};const pr=binary(p),hr=binary(h),g=geometry(pr,hr);let violations=[];if(cmp(pr,ZERO)<0||cmp(hr,ZERO)<0)violations.push('negative-family-parameter');for(let i=0;i<8;i++){if(cmp(g[i][0],P)>0||cmp(neg(g[i][0]),P)>0||cmp(g[i][1],T)>0||cmp(neg(g[i][1]),T)>0)violations.push('board:'+i);for(let j=i+1;j<8;j++)if(cmp(add(sq(sub(g[i][0],g[j][0])),sq(sub(g[i][1],g[j][1]))),ONE)<0)violations.push('distance:'+i+','+j)}return {pass:violations.length===0,violations}}let seed=20260920;function rand(){seed^=seed<<13;seed^=seed>>>17;seed^=seed<<5;return (seed>>>0)/4294967296};let samples=[];function sample(category,P,T){samples.push({id:samples.length,category,P:Number(P).toFixed(12),T:Number(T).toFixed(12)})}for(let i=0;i<16;i++){const P=1.05+.75*rand(),T=Math.max(.5,Math.sqrt(Math.max(0,1-P*P/4)))+.05+.25*rand();sample('clear-feasible',P,T)}for(let i=0;i<16;i++){if(i%3===0)sample('clear-infeasible',.7+.25*rand(),1+.5*rand());else if(i%3===1)sample('clear-infeasible',1.9+.5*rand(),.2+.25*rand());else{const P=1.05+.5*rand(),T=Math.sqrt(1-P*P/4)-.04-.04*rand();sample('clear-infeasible',P,T)}}for(const dt of [-1e-6,-1e-9,-1e-12,0,1e-12,1e-9,1e-6])sample('near-diagonal',1.2,.8+dt);for(const dp of [-1e-12,0,1e-12])sample('near-p-bound',1+dp,1);for(const dt of [-1e-12,0,1e-12])sample('near-h-bound',2,.5+dt);for(const dt of [-1e-12,0,1e-12])sample('near-diagonal',1.6,.6+dt);if(process.argv.includes('--smoke'))samples=[samples[0],samples[16],samples[35],samples[37]];(async()=>{const tLoad=performance.now(),ca=await require(path.join(ROOT,'casadi.js'))();await ca.load_nlpsol('ipopt');const loadMs=performance.now()-tLoad;const owned=[];const own=x=>(owned.push(x),x);const plus=(a,b)=>own(ca.plus(a,b)),minus=(a,b)=>own(ca.minus(a,b)),times=(a,b)=>own(ca.times(a,b)),c=x=>own(ca.SX(x));const options={error_on_fail:false,print_time:false,'ipopt.print_level':0,'ipopt.sb':'yes','ipopt.tol':1e-10,'ipopt.constr_viol_tol':1e-10,'ipopt.acceptable_iter':0,'ipopt.max_iter':300,'ipopt.max_wall_time':1,'ipopt.bound_relax_factor':0};function build(mode){const t=performance.now(),x=own(ca.SX.sym('x'+mode,mode==='A'?18:2)),q=own(ca.SX.sym('q'+mode,2)),xx=ca.vertsplit(x).map(own),qq=ca.vertsplit(q).map(own),p=xx[mode==='A'?16:0],h=xx[mode==='A'?17:1],P=qq[0],T=qq[1],z=c(0),one=c(1),minusOne=c(-1),hp=times(.5,p),np=times(-1,p),nh=times(-1,h),nhp=times(-.5,p),ideal=[[np,h],[z,h],[p,h],[nhp,z],[hp,z],[np,nh],[z,nh],[p,nh]],g=[],lbg=[],ubg=[];const append=(e,l=0,u=Infinity)=>{g.push(e);lbg.push(l);ubg.push(u)};if(mode==='A'){const pts=Array.from({length:8},(_,i)=>[xx[i*2],xx[i*2+1]]);for(let i=0;i<8;i++)for(let j=0;j<2;j++)append(minus(pts[i][j],ideal[i][j]),0,0);for(let i=0;i<8;i++)for(let j=i+1;j<8;j++){const dx=minus(pts[i][0],pts[j][0]),dy=minus(pts[i][1],pts[j][1]);append(minus(plus(times(dx,dx),times(dy,dy)),one))}for(const [a,b]of pts){append(minus(P,a));append(plus(P,a));append(minus(T,b));append(plus(T,b));}}else{append(minus(p,one));append(minus(h,.5));append(minus(plus(times(hp,hp),times(h,h)),one));append(minus(P,p));append(minus(T,h));}const gv=own(ca.vertcat(...g)),nlp={x,p:q,f:z,g:gv},symbolicMs=performance.now()-t,tBuild=performance.now(),solver=own(ca.nlpsol('feasibility_'+mode,'ipopt',nlp,options)),constructionMs=performance.now()-tBuild,lower=Array(mode==='A'?18:2).fill(-Infinity),upper=Array(mode==='A'?18:2).fill(Infinity);lower[lower.length-2]=0;lower[lower.length-1]=0;const x0=mode==='A'?numericGeometry(1,.75).flat().concat([1,.75]):[1,.75];return {mode,solver,vars:xx.length,constraints:g.length,symbolicMs,constructionMs,inputs:{x0:own(ca.DM(x0)),lbg:own(ca.DM(lbg)),ubg:own(ca.DM(ubg)),lbx:own(ca.DM(lower)),ubx:own(ca.DM(upper))}}}const models={A:build('A'),B:build('B')};function solve(model,s){const parameters=ca.DM([Number(s.P),Number(s.T)]),t=performance.now();let result,callError;try{result=model.solver.call({...model.inputs,p:parameters})}catch(e){callError=String(e)}const solveMs=performance.now()-t;let st={};try{st=model.solver.stats()}catch{}const values=result?.x?.elements?.()??[],p=values.at(-2),h=values.at(-1),tv=performance.now();let check;try{check=verify(p,h,decimal(s.P),decimal(s.T))}catch(e){check={pass:false,reason:String(e)}}let coordinateResidual=null;if(model.mode==='A'&&values.length===18){const exact=numericGeometry(p,h).flat();coordinateResidual=Math.max(...exact.map((v,i)=>Math.abs(v-values[i])))}const verifyMs=performance.now()-tv;parameters.delete();if(result)Object.values(result).forEach(v=>v.delete());return {solve_ms:solveMs,verify_ms:verifyMs,status:callError?'WebAssembly.Exception':st.return_status,success:callError?false:st.success,iterations:callError?null:st.iter_count,diagnosticStatsAfterException:callError?st:undefined,p,h,coordinateResidual,verification:check.pass?'pass':'unknown',check,callError}}const warmups=[];for(const mode of ['A','B'])for(let i=0;i<2;i++)warmups.push({mode,...solve(models[mode],{P:'1.500000000000',T:'1.000000000000'})});const records=[];for(let k=0;k<samples.length;k++){const s=samples[k],P=decimal(s.P),T=decimal(s.T),tc=performance.now(),feasible=closed(P,T),cMs=performance.now()-tc,r={...s,exactFeasible:feasible,C:{solve_ms:cMs,classification:feasible?'feasible':'infeasible',witness:feasible?{p:s.P,h:s.T}:null}};for(const mode of k%2?['B','A']:['A','B'])r[mode]=solve(models[mode],s);records.push(r)}const summary={};for(const mode of ['A','B','C']){summary[mode]={solve:stats(records.map(r=>r[mode].solve_ms))};if(mode!=='C'){summary[mode].verify=stats(records.map(r=>r[mode].verify_ms));summary[mode].normalReturnSolve=stats(records.filter(r=>!r[mode].callError).map(r=>r[mode].solve_ms));summary[mode].exceptionLatency=stats(records.filter(r=>r[mode].callError).map(r=>r[mode].solve_ms));summary[mode].passes=records.filter(r=>r[mode].verification==='pass').length;summary[mode].unknown=records.length-summary[mode].passes;summary[mode].falseFeasible=records.filter(r=>!r.exactFeasible&&r[mode].verification==='pass').length;summary[mode].statuses=Object.fromEntries([...new Set(records.map(r=>r[mode].status))].map(s=>[s,records.filter(r=>r[mode].status===s).length]));summary[mode].byCategory=Object.fromEntries([...new Set(records.map(r=>r.category))].map(cat=>{const rr=records.filter(r=>r.category===cat);return [cat,{n:rr.length,exactFeasible:rr.filter(r=>r.exactFeasible).length,passes:rr.filter(r=>r[mode].verification==='pass').length,solve:stats(rr.map(r=>r[mode].solve_ms))}]}));}}summary.C.mathematicallyFeasible=records.filter(r=>r.exactFeasible).length;summary.C.mathematicallyInfeasible=records.filter(r=>!r.exactFeasible).length;const report={environment:{node:process.version,platform:process.platform,cpu:os.cpus()[0].model,casadi:'3.8.0',ipopt:'3.14.19',seed:20260920,load_ms:loadMs},method:{D:1,zeroObjective:true,initial:{p:1,h:.75},ipoptOptions:options,records:samples.length,warmupPerModel:2,latencyScope:'A/B solve includes function call until return or exception, excludes DM parameter allocation, output extraction, stats, and exact verification. Cases returning a WebAssembly exception may expose stale stats; these stats are diagnostic only. Runtime emitted unsupported getrusage warnings, retained in TEMP stderr. This is an isolated WASM numerical-model experiment, no B-Rep operations.',independentVerification:'Exact decimal rational bounds; exact binary64 rational p,h; deterministic family backsubstitution with no p,h correction; verify all 28 distances and 32 board inequalities. Raw A coordinate residual separately reported. Any exact candidate violation is unknown, never tolerance pass.',C:'Exact rational monotone feasibility predicate, rational witness p=P,h=T; timer excludes decimal parsing and materialization. This is mathematical feasibility evidence, not a binary64 or B-Rep delivery witness. Geometry acceptance not performed. A/B verification accepts the unmodified binary64 p,h under exact backsubstitution, independently of IPOPT convergence.'},build:Object.fromEntries(Object.entries(models).map(([k,m])=>[k,{variables:m.vars,constraints:m.constraints,symbolic_ms:m.symbolicMs,solver_construction_ms:m.constructionMs}])),summary,warmups,records};console.log(JSON.stringify(report,null,2));for(const h of owned.reverse())h.delete();})().catch(e=>{console.error(e);process.exit(1)});D.2 稀疏与全部消元的凸 QP 对照
Section titled “D.2 稀疏与全部消元的凸 QP 对照”文件:aira-qp-parameterization-research-20260920.cjs。SHA-256:0046e10d0f0311554b17968777f57109af596279df08a3a26e4b818a455499ee。
运行:node aira-qp-parameterization-research-20260920.cjs。
完整复现源码
const fs=require('node:fs'),os=require('node:os'),path=require('node:path');const load=require(path.join(os.tmpdir(),'aira-highs-standalone-research-20260920','highs.js'));const stat=a=>{const b=[...a].sort((x,y)=>x-y);return {n:b.length,median_ms:b[Math.floor(b.length/2)],p95_ms:b[Math.ceil(.95*b.length)-1]}};function matrix(n,rows){const cols=Array.from({length:n},()=>[]);rows.forEach((r,k)=>r.forEach(([j,v])=>cols[j].push([k,v])));const starts=[],indices=[],values=[];for(const col of cols){starts.push(indices.length);for(const [i,v]of col){indices.push(i);values.push(v)}}starts.push(indices.length);return {format:'csc',numRows:rows.length,numCols:n,starts,indices,values};}function model(n,t,mode,inf){if(mode==='sparse'){const rows=Array.from({length:n},(_,k)=>[[k,1],...(k?[[k-1,-1]]:[]),[n+k,-1]]);return {numCols:2*n,numRows:n,colCost:[...t.map(v=>-v),...Array(n).fill(0)],colLower:[...Array(n).fill(-inf),...Array(n).fill(-.4)],colUpper:[...Array(n).fill(inf),...Array(n).fill(.4)],rowLower:Array(n).fill(0),rowUpper:Array(n).fill(0),matrix:matrix(2*n,rows),hessian:{format:'triangular',dimension:2*n,starts:Array.from({length:2*n+1},(_,k)=>k),indices:Array.from({length:2*n},(_,k)=>k),values:Array(2*n).fill(1)}};}const starts=[],indices=[],values=[],q=[];for(let j=0;j<n;j++){starts.push(indices.length);q.push(-t.slice(j).reduce((a,b)=>a+b,0));for(let i=j;i<n;i++){indices.push(i);values.push(n-i+(i===j?1:0));}}starts.push(indices.length);return {numCols:n,numRows:0,colCost:q,colLower:Array(n).fill(-.4),colUpper:Array(n).fill(.4),rowLower:[],rowUpper:[],matrix:matrix(n,[]),hessian:{format:'triangular',dimension:n,starts,indices,values}};}function inspect(v,n,t,mode){let x,u;if(mode==='sparse'){x=Array.from(v.slice(0,n));u=Array.from(v.slice(n));}else{u=Array.from(v);let s=0;x=u.map(z=>s+=z);}let violation=0,f=0;for(let i=0;i<n;i++){violation=Math.max(violation,Math.abs(u[i])-.4,Math.abs(x[i]-(i?x[i-1]:0)-u[i]));f+=.5*((x[i]-t[i])**2+u[i]**2);}return {x,u,violation,objective:f};}(async()=>{const hi=await load();let seed=8675309;const rand=()=>{seed^=seed<<13;seed^=seed>>>17;seed^=seed<<5;return (seed>>>0)/4294967296};const report={environment:{node:process.version,cpu:os.cpus()[0].model,highs:hi.version},seed:8675309,warmup:5,measured:15,scope:'same convex QP, fresh models, assembly/native load/solve separately timed; no geometry',sizes:[]};for(const n of [16,64,128]){const times={sparse:{assemble:[],load:[],solve:[],total:[]},condensed:{assemble:[],load:[],solve:[],total:[]}};let maxObjectiveDifference=0,maxCoordinateDifference=0,maxViolation=0;const counts={};for(let k=0;k<20;k++){const target=Array.from({length:n},(_,i)=>2*Math.sin((i+1)*.09)+.7*Math.cos((i+1)*.13)+(rand()-.5)*.05);const outcomes={};for(const mode of k%2?['sparse','condensed']:['condensed','sparse']){const start=performance.now(),data=model(n,target,mode,hi.infinity),assembled=performance.now(),m=hi.createModel(data);try{m.options.set({output_flag:false});const loaded=performance.now(),result=m.run(),solved=performance.now();if(result.modelStatus!==7)throw new Error('not optimal '+mode+' '+n+' '+JSON.stringify(result));outcomes[mode]=inspect(m.getSolution().colValue,n,target,mode);maxViolation=Math.max(maxViolation,outcomes[mode].violation);counts[mode]={variables:data.numCols,equalities:data.numRows,matrixNnz:data.matrix.values.length,hessianStoredNnz:data.hessian.values.length};if(k>=5){times[mode].assemble.push(assembled-start);times[mode].load.push(loaded-assembled);times[mode].solve.push(solved-loaded);times[mode].total.push(solved-start);}}finally{m.dispose()}}maxObjectiveDifference=Math.max(maxObjectiveDifference,Math.abs(outcomes.sparse.objective-outcomes.condensed.objective));maxCoordinateDifference=Math.max(maxCoordinateDifference,...outcomes.sparse.x.map((v,i)=>Math.abs(v-outcomes.condensed.x[i])));}report.sizes.push({n,counts,maxObjectiveDifference,maxCoordinateDifference,maxViolation,times:Object.fromEntries(Object.entries(times).map(([mode,parts])=>[mode,Object.fromEntries(Object.entries(parts).map(([p,a])=>[p,stat(a)]))]))});}const out=JSON.stringify(report,null,2);fs.writeFileSync(path.join(os.tmpdir(),'aira-qp-parameterization-research-20260920.json'),out);console.log(out);})();D.3 部分消元的校准对照
Section titled “D.3 部分消元的校准对照”文件:aira-qp-partial-condensing-research-20260920.cjs。SHA-256:df77bbec82a1250690de663315f03151f6866770766d0d5ad49a69456b2aa7df。
运行:node aira-qp-partial-condensing-research-20260920.cjs。
完整复现源码
const fs=require('node:fs'),os=require('node:os'),path=require('node:path');const load=require(path.join(os.tmpdir(),'aira-highs-standalone-research-20260920','highs.js'));const stat=a=>{const b=[...a].sort((x,y)=>x-y);return {n:b.length,p50_ms:b[Math.floor(b.length/2)],p95_ms:b[Math.ceil(.95*b.length)-1],min_ms:b[0],max_ms:b.at(-1)}};function matrix(n,rows){const cols=Array.from({length:n},()=>[]);rows.forEach((r,k)=>r.forEach(([j,v])=>cols[j].push([k,v])));const starts=[],indices=[],values=[];for(const col of cols){starts.push(indices.length);for(const [i,v]of col){indices.push(i);values.push(v)}}starts.push(indices.length);return {format:'csc',numRows:rows.length,numCols:n,starts,indices,values};}function direct(n,t,B,inf){B=Math.min(B,n);const M=Math.ceil(n/B),V=n+M-1,q=Array(V).fill(0),starts=[],indices=[],values=[];for(let b=0;b<M;b++){const begin=b*B,L=Math.min(B,n-begin);let suffix=0;for(let j=L-1;j>=0;j--){suffix+=t[begin+j];q[begin+j]=-suffix}if(b)q[n+b-1]=-suffix;for(let j=0;j<L;j++){starts.push(indices.length);for(let i=j;i<L;i++){indices.push(begin+i);values.push(L-i+(i===j?1:0))}if(b){indices.push(n+b-1);values.push(L-j)}}}for(let b=1;b<M;b++){starts.push(indices.length);indices.push(n+b-1);values.push(Math.min(B,n-b*B))}starts.push(indices.length);const rows=[];for(let b=0;b<M-1;b++){const row=[[n+b,1]];if(b)row.push([n+b-1,-1]);for(let j=0;j<Math.min(B,n-b*B);j++)row.push([b*B+j,-1]);rows.push(row)}return {numCols:V,numRows:rows.length,colCost:q,offset:t.reduce((s,z)=>s+.5*z*z,0),colLower:[...Array(n).fill(-.4),...Array(M-1).fill(-inf)],colUpper:[...Array(n).fill(.4),...Array(M-1).fill(inf)],rowLower:Array(rows.length).fill(0),rowUpper:Array(rows.length).fill(0),matrix:matrix(V,rows),hessian:{format:'triangular',dimension:V,starts,indices,values}};}function generic(n,t,B,inf){const data=direct(n,t,B,inf),V=data.numCols,M=Math.ceil(n/B),H=Array.from({length:V},()=>new Map()),q=Array(V).fill(0);for(let u=0;u<n;u++)H[u].set(u,1);for(let b=0;b<M;b++){const begin=b*B,L=Math.min(B,n-begin);for(let j=0;j<L;j++){const a=[];for(let i=0;i<=j;i++)a.push([begin+i,1]);if(b)a.push([n+b-1,1]);for(const [i,v]of a)q[i]-=t[begin+j]*v;for(const [col,a0]of a)for(const [row,a1]of a)if(row>=col)H[col].set(row,(H[col].get(row)??0)+a0*a1)}}const starts=[],indices=[],values=[];for(const col of H){starts.push(indices.length);for(const [row,v]of [...col].sort((a,b)=>a[0]-b[0])){indices.push(row);values.push(v)}}starts.push(indices.length);return {...data,colCost:q,hessian:{format:'triangular',dimension:V,starts,indices,values}};}function inspect(v,n,t,B){const u=Array.from(v.slice(0,n)),x=[],M=Math.ceil(n/B);for(let b=0;b<M;b++){let s=b?v[n+b-1]:0;for(let j=0;j<Math.min(B,n-b*B);j++){s+=u[b*B+j];x.push(s)}}let violation=0,objective=0,grad=0,kkt=0;for(let i=n-1;i>=0;i--){violation=Math.max(violation,Math.abs(u[i])-.4,Math.abs(x[i]-(i?x[i-1]:0)-u[i]));objective+=.5*((x[i]-t[i])**2+u[i]**2);grad+=x[i]-t[i];const g=grad+u[i];kkt=Math.max(kkt,u[i]<=-.4+1e-7?Math.max(0,-g):u[i]>=.4-1e-7?Math.max(0,g):Math.abs(g))}return {x,u,violation,objective,kkt};}(async()=>{const h=await load(),smoke=process.argv.includes('--smoke'),warm=smoke?1:3,measured=smoke?2:9,probe=h.createModel(),defaults={};for(const key of ['solver','primal_feasibility_tolerance','dual_feasibility_tolerance','qp_regularization_value']){try{defaults[key]=probe.options.describe(key)}catch(e){defaults[key]={error:String(e)}}}probe.dispose();const crossChecks=[];for(const [n,B]of [[7,1],[7,2],[7,3],[7,7],[17,4],[19,6]]){const t=Array.from({length:n},(_,i)=>Math.sin(i)*.37),a=direct(n,t,B,h.infinity),b=generic(n,t,B,h.infinity);if(JSON.stringify(a.hessian)!==JSON.stringify(b.hessian))throw new Error('H mismatch '+n+','+B);const qDiff=Math.max(...a.colCost.map((v,i)=>Math.abs(v-b.colCost[i])));if(qDiff>1e-12)throw new Error('q mismatch');crossChecks.push({n,B,hessianExactlyEqual:true,maxQDifference:qDiff})}let seed=8675309;const rand=()=>{seed^=seed<<13;seed^=seed>>>17;seed^=seed<<5;return(seed>>>0)/4294967296};const report={environment:{node:process.version,platform:process.platform,cpu:os.cpus()[0].model,highs:h.version,defaultOptions:defaults},seed:8675309,warmup:warm,measured,scope:'Equivalent convex chain QP with controls u in [-0.4,0.4]. B=1 retains block starts but omits terminal xN (2N-1 variables), not original 2N-variable sparse model. B=N is full condensing. Formal timings use direct O(NB) stored-coefficient construction, checked against generic sparse rank-one assembly on small, including non-divisible, cases. Fresh native model per attempt; same target per block size each round; rotating/reversing execution order. Total is assemble+load+solve, excludes getSolution, validation, comparison and dispose. Floating diagnostic checks do not constitute exact certificates.',crossChecks,sizes:[]};for(const n of(smoke?[128]:[128,256,512])){const blocks=[1,4,16,64,n],timings=Object.fromEntries(blocks.map(B=>[B,{assemble:[],load:[],solve:[],total:[]}])) ,counts={},differences=Object.fromEntries(blocks.map(B=>[B,{maxObjectiveDifference:0,maxPrimalDifference:0,maxViolation:0,maxKktDiagnostic:0}])),records=[];for(let k=0;k<warm+measured;k++){const t=Array.from({length:n},(_,i)=>2*Math.sin((i+1)*.09)+.7*Math.cos((i+1)*.13)+(rand()-.5)*.05),order=[...blocks.slice(k%blocks.length),...blocks.slice(0,k%blocks.length)];if(Math.floor(k/blocks.length)%2)order.reverse();const outcome={},row={trial:k,warmup:k<warm,target:t,order,modes:{}};for(const B of order){const start=performance.now(),data=direct(n,t,B,h.infinity),assembled=performance.now(),m=h.createModel(data);try{m.options.set({output_flag:false});const loaded=performance.now(),result=m.run(),solved=performance.now();if(result.modelStatus!==7)throw new Error('not optimal '+n+','+B+' '+JSON.stringify(result));outcome[B]=inspect(m.getSolution().colValue,n,t,B);const r={assemble_ms:assembled-start,load_ms:loaded-assembled,solve_ms:solved-loaded,total_ms:solved-start,violation:outcome[B].violation,kktDiagnostic:outcome[B].kkt,objective:outcome[B].objective,qpIterations:m.info.get('qp_iteration_count')};row.modes[B]=r;counts[B]={variables:data.numCols,equalities:data.numRows,matrixNnz:data.matrix.values.length,hessianStoredNnz:data.hessian.values.length};if(k>=warm)for(const part of ['assemble','load','solve','total'])timings[B][part].push(r[part+'_ms']);}finally{m.dispose()}}const baseline=outcome[n];for(const B of blocks){const r=outcome[B],d=differences[B],f=Math.abs(r.objective-baseline.objective),p=Math.max(...r.x.map((x,i)=>Math.abs(x-baseline.x[i])),...r.u.map((x,i)=>Math.abs(x-baseline.u[i])));Object.assign(row.modes[B],{objectiveDifferenceFromFull:f,primalDifferenceFromFull:p});d.maxObjectiveDifference=Math.max(d.maxObjectiveDifference,f);d.maxPrimalDifference=Math.max(d.maxPrimalDifference,p);d.maxViolation=Math.max(d.maxViolation,r.violation);d.maxKktDiagnostic=Math.max(d.maxKktDiagnostic,r.kkt)}records.push(row)}const size={n,counts,differences,times:Object.fromEntries(blocks.map(B=>[B,Object.fromEntries(Object.entries(timings[B]).map(([p,v])=>[p,stat(v)]))])),records};report.sizes.push(size);console.error(JSON.stringify({completedN:n,totalP50ByBlock:Object.fromEntries(blocks.map(B=>[B,size.times[B].total.p50_ms]))}));}const output=path.join(os.tmpdir(),smoke?'aira-qp-partial-condensing-research-20260920-smoke.json':'aira-qp-partial-condensing-research-20260920.json');fs.writeFileSync(output,JSON.stringify(report,null,2));console.log(JSON.stringify({output,...report,sizes:report.sizes.map(({records,...rest})=>rest)},null,2));})().catch(e=>{console.error(e);process.exit(1)});D.4 部分消元的独立留出
Section titled “D.4 部分消元的独立留出”文件:aira-qp-partial-condensing-holdout-20260921.cjs。SHA-256:22993065bb0e29a71c3329329d3b75351c8cb833d8e1741f70d1f734bdcdece8。
运行:node aira-qp-partial-condensing-holdout-20260921.cjs。
完整复现源码
const fs=require('node:fs'),os=require('node:os'),path=require('node:path');const load=require(path.join(os.tmpdir(),'aira-highs-standalone-research-20260920','highs.js'));const stat=a=>{const b=[...a].sort((x,y)=>x-y);return {n:b.length,p50_ms:b[Math.floor(b.length/2)],p95_ms:b[Math.ceil(.95*b.length)-1],min_ms:b[0],max_ms:b.at(-1)}};function matrix(n,rows){const cols=Array.from({length:n},()=>[]);rows.forEach((r,k)=>r.forEach(([j,v])=>cols[j].push([k,v])));const starts=[],indices=[],values=[];for(const col of cols){starts.push(indices.length);for(const [i,v]of col){indices.push(i);values.push(v)}}starts.push(indices.length);return {format:'csc',numRows:rows.length,numCols:n,starts,indices,values};}function direct(n,t,B,inf){B=Math.min(B,n);const M=Math.ceil(n/B),V=n+M-1,q=Array(V).fill(0),starts=[],indices=[],values=[];for(let b=0;b<M;b++){const begin=b*B,L=Math.min(B,n-begin);let suffix=0;for(let j=L-1;j>=0;j--){suffix+=t[begin+j];q[begin+j]=-suffix}if(b)q[n+b-1]=-suffix;for(let j=0;j<L;j++){starts.push(indices.length);for(let i=j;i<L;i++){indices.push(begin+i);values.push(L-i+(i===j?1:0))}if(b){indices.push(n+b-1);values.push(L-j)}}}for(let b=1;b<M;b++){starts.push(indices.length);indices.push(n+b-1);values.push(Math.min(B,n-b*B))}starts.push(indices.length);const rows=[];for(let b=0;b<M-1;b++){const row=[[n+b,1]];if(b)row.push([n+b-1,-1]);for(let j=0;j<Math.min(B,n-b*B);j++)row.push([b*B+j,-1]);rows.push(row)}return {numCols:V,numRows:rows.length,colCost:q,offset:t.reduce((s,z)=>s+.5*z*z,0),colLower:[...Array(n).fill(-.4),...Array(M-1).fill(-inf)],colUpper:[...Array(n).fill(.4),...Array(M-1).fill(inf)],rowLower:Array(rows.length).fill(0),rowUpper:Array(rows.length).fill(0),matrix:matrix(V,rows),hessian:{format:'triangular',dimension:V,starts,indices,values}};}function generic(n,t,B,inf){const data=direct(n,t,B,inf),V=data.numCols,M=Math.ceil(n/B),H=Array.from({length:V},()=>new Map()),q=Array(V).fill(0);for(let u=0;u<n;u++)H[u].set(u,1);for(let b=0;b<M;b++){const begin=b*B,L=Math.min(B,n-begin);for(let j=0;j<L;j++){const a=[];for(let i=0;i<=j;i++)a.push([begin+i,1]);if(b)a.push([n+b-1,1]);for(const [i,v]of a)q[i]-=t[begin+j]*v;for(const [col,a0]of a)for(const [row,a1]of a)if(row>=col)H[col].set(row,(H[col].get(row)??0)+a0*a1)}}const starts=[],indices=[],values=[];for(const col of H){starts.push(indices.length);for(const [row,v]of [...col].sort((a,b)=>a[0]-b[0])){indices.push(row);values.push(v)}}starts.push(indices.length);return {...data,colCost:q,hessian:{format:'triangular',dimension:V,starts,indices,values}};}function inspect(v,n,t,B){const u=Array.from(v.slice(0,n)),x=[],M=Math.ceil(n/B);for(let b=0;b<M;b++){let s=b?v[n+b-1]:0;for(let j=0;j<Math.min(B,n-b*B);j++){s+=u[b*B+j];x.push(s)}}let violation=0,objective=0,grad=0,kkt=0;for(let i=n-1;i>=0;i--){violation=Math.max(violation,Math.abs(u[i])-.4,Math.abs(x[i]-(i?x[i-1]:0)-u[i]));objective+=.5*((x[i]-t[i])**2+u[i]**2);grad+=x[i]-t[i];const g=grad+u[i];kkt=Math.max(kkt,u[i]<=-.4+1e-7?Math.max(0,-g):u[i]>=.4-1e-7?Math.max(0,g):Math.abs(g))}return {x,u,violation,objective,kkt};}(async()=>{const h=await load(),smoke=process.argv.includes('--smoke'),warm=smoke?1:5,measured=smoke?2:24,probe=h.createModel(),defaults={};for(const key of ['solver','primal_feasibility_tolerance','dual_feasibility_tolerance','qp_regularization_value']){try{defaults[key]=probe.options.describe(key)}catch(e){defaults[key]={error:String(e)}}}probe.dispose();const crossChecks=[];for(const [n,B]of [[7,1],[7,2],[7,3],[7,7],[17,4],[19,6]]){const t=Array.from({length:n},(_,i)=>Math.sin(i)*.37),a=direct(n,t,B,h.infinity),b=generic(n,t,B,h.infinity);if(JSON.stringify(a.hessian)!==JSON.stringify(b.hessian))throw new Error('H mismatch '+n+','+B);const qDiff=Math.max(...a.colCost.map((v,i)=>Math.abs(v-b.colCost[i])));if(qDiff>1e-12)throw new Error('q mismatch');crossChecks.push({n,B,hessianExactlyEqual:true,maxQDifference:qDiff})}let seed=20260921;const rand=()=>{seed^=seed<<13;seed^=seed>>>17;seed^=seed<<5;return(seed>>>0)/4294967296};const report={environment:{node:process.version,platform:process.platform,cpu:os.cpus()[0].model,highs:h.version,defaultOptions:defaults},seed:20260921,warmup:warm,measured,scope:'Independent seed holdout in the same sinusoidal-target-plus-noise family, after block-size calibration. Equivalent convex chain QP with controls u in [-0.4,0.4]. B=1 retains block starts but omits terminal xN (2N-1 variables), not original 2N-variable sparse model. B=N is full condensing. Formal timings use direct O(NB) stored-coefficient construction, checked against generic sparse rank-one assembly on small, including non-divisible, cases. Fresh native model per attempt; same target per block size each round; rotating/reversing execution order. Total is assemble+load+solve, excludes getSolution, validation, comparison and dispose. Floating diagnostic checks do not constitute exact certificates.',crossChecks,sizes:[]};for(const n of(smoke?[512]:[512])){const blocks=[16,64,n],timings=Object.fromEntries(blocks.map(B=>[B,{assemble:[],load:[],solve:[],total:[]}])) ,counts={},differences=Object.fromEntries(blocks.map(B=>[B,{maxObjectiveDifference:0,maxPrimalDifference:0,maxViolation:0,maxKktDiagnostic:0}])),records=[];for(let k=0;k<warm+measured;k++){const t=Array.from({length:n},(_,i)=>2*Math.sin((i+1)*.09)+.7*Math.cos((i+1)*.13)+(rand()-.5)*.05),order=[...blocks.slice(k%blocks.length),...blocks.slice(0,k%blocks.length)];if(Math.floor(k/blocks.length)%2)order.reverse();const outcome={},row={trial:k,warmup:k<warm,target:t,order,modes:{}};for(const B of order){const start=performance.now(),data=direct(n,t,B,h.infinity),assembled=performance.now(),m=h.createModel(data);try{m.options.set({output_flag:false});const loaded=performance.now(),result=m.run(),solved=performance.now();if(result.modelStatus!==7)throw new Error('not optimal '+n+','+B+' '+JSON.stringify(result));outcome[B]=inspect(m.getSolution().colValue,n,t,B);const r={assemble_ms:assembled-start,load_ms:loaded-assembled,solve_ms:solved-loaded,total_ms:solved-start,violation:outcome[B].violation,kktDiagnostic:outcome[B].kkt,objective:outcome[B].objective,qpIterations:m.info.get('qp_iteration_count')};row.modes[B]=r;counts[B]={variables:data.numCols,equalities:data.numRows,matrixNnz:data.matrix.values.length,hessianStoredNnz:data.hessian.values.length};if(k>=warm)for(const part of ['assemble','load','solve','total'])timings[B][part].push(r[part+'_ms']);}finally{m.dispose()}}const baseline=outcome[n];for(const B of blocks){const r=outcome[B],d=differences[B],f=Math.abs(r.objective-baseline.objective),p=Math.max(...r.x.map((x,i)=>Math.abs(x-baseline.x[i])),...r.u.map((x,i)=>Math.abs(x-baseline.u[i])));Object.assign(row.modes[B],{objectiveDifferenceFromFull:f,primalDifferenceFromFull:p});d.maxObjectiveDifference=Math.max(d.maxObjectiveDifference,f);d.maxPrimalDifference=Math.max(d.maxPrimalDifference,p);d.maxViolation=Math.max(d.maxViolation,r.violation);d.maxKktDiagnostic=Math.max(d.maxKktDiagnostic,r.kkt)}records.push(row)}const numericalChecks=Object.fromEntries(blocks.map(B=>{const rr=records.filter(r=>!r.warmup).map(r=>r.modes[B]);const scalar=k=>{const a=rr.map(r=>r[k]).sort((a,b)=>a-b);return {n:a.length,p50:a[Math.floor(a.length/2)],p95:a[Math.ceil(.95*a.length)-1],max:a.at(-1)}};return [B,{kktDiagnostic:scalar('kktDiagnostic'),violation:scalar('violation'),objectiveDifferenceFromFull:scalar('objectiveDifferenceFromFull'),primalDifferenceFromFull:scalar('primalDifferenceFromFull')}] }));const size={n,counts,differences,numericalChecks,times:Object.fromEntries(blocks.map(B=>[B,Object.fromEntries(Object.entries(timings[B]).map(([p,v])=>[p,stat(v)]))])),records};report.sizes.push(size);console.error(JSON.stringify({completedN:n,totalP50ByBlock:Object.fromEntries(blocks.map(B=>[B,size.times[B].total.p50_ms]))}));}const output=path.join(os.tmpdir(),smoke?'aira-qp-partial-condensing-holdout-20260921-smoke.json':'aira-qp-partial-condensing-holdout-20260921.json');fs.writeFileSync(output,JSON.stringify(report,null,2));console.log(JSON.stringify({output,...report,sizes:report.sizes.map(({records,...rest})=>rest)},null,2));})().catch(e=>{console.error(e);process.exit(1)});D.5 真实 OCCT 构造对照
Section titled “D.5 真实 OCCT 构造对照”文件:aira-occt-construction-20260920/occt-construction-comparison.mjs。SHA-256:e55963258ea040c4b1338e6ba3da7a5ee8c52215b8eb7e5b78d5644fd3944e1f。
运行:node occt-construction-comparison.mjs。
完整复现源码
import fs from 'node:fs';import crypto from 'node:crypto';import os from 'node:os';import { performance } from 'node:perf_hooks';import { pathToFileURL, fileURLToPath } from 'node:url';const root='<workspace-root>';const runtime=root+'/packages/aira-geometry-kernel/runtime/feature-graph/aira_occt_feature_graph';const t0=performance.now();const {default:init}=await import(pathToFileURL(runtime+'.js'));const t1=performance.now();const wasmBinary=fs.readFileSync(runtime+'.wasm');const t2=performance.now();const oc=await init({wasmBinary});const t3=performance.now();const input={width:80,height:30,thickness:4,radius:3,centres:[10,30,50,70].flatMap(x=>[10,20].map(y=>[x,y]))};const expectedVolume=input.width*input.height*input.thickness-input.centres.length*Math.PI*input.radius**2*input.thickness;function scope(fn){const xs=[]; const hold=x=>(xs.push(x),x);try{return fn(hold);}finally{for(let i=xs.length-1;i>=0;i--)xs[i].delete();}}function point(hold,x,y,z){return hold(new oc.gp_Pnt(x,y,z));}function axis(hold,x,y,z){return hold(new oc.gp_Ax2(point(hold,x,y,z),hold(new oc.gp_Dir(0,0,1))));}function cutRecipe(){return scope(h=>{ const baseMaker=h(new oc.BRepPrimAPI_MakeBox(input.width,input.height,input.thickness)); const base=h(baseMaker.Shape()); const compound=h(new oc.TopoDS_Compound()); const builder=h(new oc.TopoDS_Builder()); builder.MakeCompound(compound); for(const [x,y] of input.centres){ const maker=h(new oc.BRepPrimAPI_MakeCylinder(axis(h,x,y,-1),input.radius,input.thickness+2)); const shape=h(maker.Shape()); builder.Add(compound,shape); } const progress=h(new oc.Message_ProgressRange()); const cut=h(oc.airaNonDestructiveCut(base,compound,progress)); if(cut.HasErrors())throw new Error('Cut HasErrors'); return cut.Shape();});}function prismRecipe(){return scope(h=>{ const poly=h(new oc.BRepBuilderAPI_MakePolygon()); for(const [x,y] of [[0,0],[input.width,0],[input.width,input.height],[0,input.height]])poly.Add(point(h,x,y,0)); poly.Close(); const outer=h(poly.Wire()); const faceMaker=h(new oc.BRepBuilderAPI_MakeFace(outer,false)); for(const [x,y] of input.centres){ const circle=h(new oc.gp_Circ(axis(h,x,y,0),input.radius)); const edgeMaker=h(new oc.BRepBuilderAPI_MakeEdge(circle)); const edge=h(edgeMaker.Edge());const wireMaker=h(new oc.BRepBuilderAPI_MakeWire(edge)); const wire=h(wireMaker.Wire()); wire.Reverse();faceMaker.Add(wire); } if(!faceMaker.IsDone())throw new Error('Face NotDone'); const face=h(faceMaker.Face());const vec=h(new oc.gp_Vec(0,0,input.thickness)); const prism=h(new oc.BRepPrimAPI_MakePrism(face,vec,false,true)); if(!prism.IsDone())throw new Error('Prism NotDone'); return prism.Shape();});}function uniqueMembers(shape,kind,fn){return scope(h=>{ const exp=h(new oc.TopExp_Explorer(shape,kind,oc.TopAbs_ShapeEnum.TopAbs_SHAPE)); const list=[]; while(exp.More()){const item=h(exp.Current());if(!list.some(x=>x.IsSame(item)))list.push(item);exp.Next();} return fn(list,h);});}function inspect(shape){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 topology={};for(const [name,kind] of [['solids','TopAbs_SOLID'],['shells','TopAbs_SHELL'],['faces','TopAbs_FACE'],['edges','TopAbs_EDGE'],['vertices','TopAbs_VERTEX']])topology[name]=uniqueMembers(shape,oc.TopAbs_ShapeEnum[kind],members=>members.length); const surfaces=uniqueMembers(shape,oc.TopAbs_ShapeEnum.TopAbs_FACE,(members,take)=>{ const cylinders=[];let planes=0;const planeWireCounts=[]; for(const item of members){ const face=take(oc.TopoDS.Face(item));const adaptor=take(new oc.BRepAdaptor_Surface(face,true)); if(adaptor.GetType()===oc.GeomAbs_SurfaceType.GeomAbs_Cylinder){ const cyl=take(adaptor.Cylinder());const loc=take(cyl.Location());const ax=take(cyl.Axis());const dir=take(ax.Direction()); cylinders.push({x:loc.X(),y:loc.Y(),radius:cyl.Radius(),axis:[dir.X(),dir.Y(),dir.Z()],uSpan:adaptor.LastUParameter()-adaptor.FirstUParameter(),vSpan:adaptor.LastVParameter()-adaptor.FirstVParameter()}); } else if(adaptor.GetType()===oc.GeomAbs_SurfaceType.GeomAbs_Plane){planes++;planeWireCounts.push(uniqueMembers(face,oc.TopAbs_ShapeEnum.TopAbs_WIRE,ws=>ws.length));} } cylinders.sort((a,b)=>a.x-b.x||a.y-b.y);planeWireCounts.sort((a,b)=>a-b);return {cylinders,planes,planeWireCounts}; }); const volume=props.Mass();const measuredBounds={min:[bounds.GetXMin(),bounds.GetYMin(),bounds.GetZMin()],max:[bounds.GetXMax(),bounds.GetYMax(),bounds.GetZMax()]}; const holeCheck=surfaces.cylinders.length===8&&surfaces.cylinders.every((c,i)=>Math.abs(c.x-input.centres[i][0])<1e-8&&Math.abs(c.y-input.centres[i][1])<1e-8&&Math.abs(c.radius-input.radius)<1e-8&&Math.abs(c.uSpan-2*Math.PI)<1e-8&&Math.abs(c.vSpan-input.thickness)<1e-8&&Math.abs(Math.abs(c.axis[2])-1)<1e-8); const volumeError=Math.abs(volume-expectedVolume); const passed=analyzer.IsValid()&&topology.solids===1&&topology.shells===1&&topology.faces===14&&holeCheck&&volumeError<1e-7&&JSON.stringify(surfaces.planeWireCounts)==='[1,1,1,1,9,9]'; return {passed,valid:analyzer.IsValid(),exactAnalyzerMethod:analyzer.IsExactMethod(),volume,expectedVolume,volumeError,topology,bounds:measuredBounds,...surfaces,holeCheck};});}const recipes={A_compoundCut:cutRecipe,B_innerWiresPrism:prismRecipe};const rows=[];const warmup=3,measured=20;for(let i=-warmup;i<measured;i++){ const order=Math.abs(i)%2===0?Object.keys(recipes):Object.keys(recipes).reverse(); for(const method of order){const start=performance.now();const shape=recipes[method]();const built=performance.now();let check; try{check=inspect(shape);if(!check.passed)throw new Error(JSON.stringify({method,check}));}finally{shape.delete();} if(i>=0)rows.push({iteration:i,method,constructionMs:built-start,verificationAndResultDisposalMs:performance.now()-built,check}); }}const quantile=(a,p)=>{const v=[...a].sort((x,y)=>x-y);return v[Math.ceil(p*v.length)-1];};const summary=Object.fromEntries(Object.keys(recipes).map(method=>{const r=rows.filter(x=>x.method===method);const c=r.map(x=>x.constructionMs);return [method,{n:r.length,medianMs:quantile(c,.5),p95Ms:quantile(c,.95),minMs:Math.min(...c),maxMs:Math.max(...c),verificationMedianMs:quantile(r.map(x=>x.verificationAndResultDisposalMs),.5),verificationP95Ms:quantile(r.map(x=>x.verificationAndResultDisposalMs),.95),totalMedianMs:quantile(r.map(x=>x.constructionMs+x.verificationAndResultDisposalMs),.5),totalP95Ms:quantile(r.map(x=>x.constructionMs+x.verificationAndResultDisposalMs),.95),allChecksPassed:r.every(x=>x.check.passed),representative:r[0].check}];}));const result={kind:'isolated-native-OCCT-construction-comparison',createdAt:new Date().toISOString(),node:process.version,platform:process.platform,arch:process.arch,cpu:os.cpus()[0]?.model,input,environment:{runtime,wasmSha256:crypto.createHash('sha256').update(wasmBinary).digest('hex'),jsSha256:crypto.createHash('sha256').update(fs.readFileSync(runtime+'.js')).digest('hex'),wasmBytes:wasmBinary.length,initialization:{jsImportMs:t1-t0,wasmReadMs:t2-t1,wasmInitializeMs:t3-t2,totalMs:t3-t0}},protocol:{warmupPerMethod:warmup,measuredPerMethod:measured,alternatingOrder:true,constructionIncludes:'all per-sample native input creation, final construction, intermediate handle disposal',constructionExcludes:'module initialization, verification, final result handle disposal, product AMIR/lineage/transaction, solver time',initializationScope:'one new Node process, OS file-cache state uncontrolled; not a browser cold-start benchmark',identity:'same geometric intent; distinct construction and topology histories, no stable-name equivalence claimed'},summary,rows};const json=fileURLToPath(new URL('./occt-construction-comparison.json',import.meta.url));fs.writeFileSync(json,JSON.stringify(result,null,2));console.log(JSON.stringify({json,initialization:result.environment.initialization,summary},null,2));