// Exploratory model, not production code or a test of the Rust implementation. const fs = require('fs'); const assert = require('assert/strict'); let count = 0, graphCount = 0, admitted = 0, refused = 0, noops = 0; function* permutations(a) { if (!a.length) { yield []; return; } for (let i=0;ii!==j))) yield [a[i],...tail]; } function* partitions(n, prefix=[]) { if(prefix.length===n) { yield prefix; return; } const max=prefix.length?Math.max(...prefix)+1:0; for(let x=0;x<=max;x++) yield* partitions(n,[...prefix,x]); } function plan(steps, ranks, selected, rawGap) { const rank=ranks[selected[0]]; if(!selected.length || selected.some(id=>ranks[id]!==rank)) return null; const indices=steps.flatMap((id,i)=>ranks[id]===rank?[i]:[]); const column=indices.map(i=>steps[i]), set=new Set(selected); assert(rawGap>=0 && rawGap<=column.length); const block=column.filter(id=>set.has(id)); const remainder=column.filter(id=>!set.has(id)); const gap=column.slice(0,rawGap).filter(id=>!set.has(id)).length; const order=[...remainder.slice(0,gap),...block,...remainder.slice(gap)]; const result=steps.slice(); indices.forEach((index,i)=>result[index]=order[i]); return {result, order, gap, changed:result.some((id,i)=>id!==steps[i])}; } function verify(steps,ranks,selected,rawGap,p) { const set=new Set(selected), rank=ranks[selected[0]]; const old=steps.filter(id=>ranks[id]===rank), got=p.result.filter(id=>ranks[id]===rank); assert.deepEqual([...p.result].sort(),[...steps].sort()); steps.forEach((id,i)=>{if(ranks[id]!==rank) assert.equal(p.result[i],id);}); assert.deepEqual(got.filter(id=>set.has(id)),old.filter(id=>set.has(id))); assert.deepEqual(got.filter(id=>!set.has(id)),old.filter(id=>!set.has(id))); const first=got.findIndex(id=>set.has(id)); assert.equal(got.slice(first,first+set.size).every(id=>set.has(id)),true); // Independent gap oracle: every original unselected item before boundary // precedes every selected item; all remaining unselected items follow them. old.forEach((id,i)=>{if(!set.has(id)) selected.forEach(s=>assert.equal(got.indexOf(id)id===got[i]); assert.equal(p.changed,!stableAlready); const source=JSON.stringify({steps,untouched:'sentinel'}); const after=p.changed?JSON.stringify({steps:p.result,untouched:'sentinel'}):source; if(stableAlready) {assert.equal(after,source); noops++;} count++; } for(let n=1;n<=5;n++) { const ids=Array.from({length:n},(_,i)=>i); for(const ranks of partitions(n)) for(const steps of permutations(ids)) { for(let mask=1;mask<(1<mask&(1<ranks[id]!==ranks[selected[0]])) { assert.equal(plan(steps,ranks,selected,0),null); refused++; continue; } const column=steps.filter(id=>ranks[id]===ranks[selected[0]]); const equivalents=new Map(); for(let gap=0;gap<=column.length;gap++) { const p=plan(steps,ranks,selected,gap); verify(steps,ranks,selected,gap,p); assert.deepEqual(p,plan(steps,ranks,[...selected].reverse(),gap)); if(equivalents.has(p.gap)) assert.deepEqual(p.result,equivalents.get(p.gap)); equivalents.set(p.gap,p.result); } } } } // Semantic column model: longest-path Kahn ranks and deterministic residual // fallback, matching the documented algorithm, independently of planner. function ranksOf(steps,edges) { const indegree=Object.fromEntries(steps.map(id=>[id,0])); const ranks=Object.fromEntries(steps.map(id=>[id,0])); edges.forEach(([,b])=>indegree[b]++); const queue=steps.filter(id=>indegree[id]===0), done=new Set(); for(let i=0;i{if(!done.has(id))ranks[id]=fallback++;}); return ranks; } const ids=[0,1,2,3], possible=ids.flatMap(a=>ids.filter(b=>a!==b).map(b=>[a,b])); for(let mask=0;mask<(1<mask&(1<subset&(1<ranks[id]!==ranks[selected[0]]))continue; const column=steps.filter(id=>ranks[id]===ranks[selected[0]]); for(let gap=0;gap<=column.length;gap++) { const p=plan(steps,ranks,selected,gap); assert.deepEqual(ranksOf(p.result,edges),ranks); admitted++; } } } } const concrete=[]; function example(name,steps,ranks,selected,gap,expected) { const p=plan(steps,ranks,selected,gap); assert.deepEqual(p?.result??null,expected); concrete.push({name,steps,ranks,selected,rawGap:gap,result:p?.result??null,changed:p?.changed??false}); } example('interleaved visual no-op',['a','u','b','v','c'],{a:0,b:0,c:0,u:1,v:1},['c','b'],1,['a','u','b','v','c']); example('column slot move preserves other indices',['a','u','b','v','c'],{a:0,b:0,c:0,u:1,v:1},['c','b'],0,['b','u','c','v','a']); example('selected-anchor normalization is not always no-op',['a','b','c','d'],{a:0,b:0,c:0,d:0},['b','d'],3,['a','c','b','d']); example('legacy successive-rank refusal',['a','b','c'],{a:0,b:1,c:2},['a','c'],0,null); const cyclicRanks=ranksOf([0,1,2,3],[[2,3],[3,2]]); example('cycle fallback group refusal',[0,1,2,3],cyclicRanks,[2,3],0,null); example('acyclic peers beside cycle',[0,1,2,3],cyclicRanks,[1],0,[1,0,2,3]); const besideCycleSteps=['a','u','b','v','c'], besideCycleEdges=[['u','v'],['v','u']]; const besideCycleRanks=ranksOf(besideCycleSteps,besideCycleEdges); example('changed multiple-member group beside cycle',besideCycleSteps,besideCycleRanks,['c','b'],0,['b','u','c','v','a']); assert.deepEqual(ranksOf(['b','u','c','v','a'],besideCycleEdges),besideCycleRanks); const result={expectation:'Column-slot permutation satisfies stable-block/gap/index invariants; recomputed ranks remain exact.',method:'All permutations and set partitions through n=5; every nonempty subset and raw column gap. Every directed simple graph on 4 IDs, all 24 step permutations, all admitted subsets/gaps. No Rust, source serializer, or GUI exercised.',passed:true,counts:{propertyCases:count,crossColumnRefusals:refused,noops,graphOrders:graphCount,rankCheckedPlans:admitted},concrete}; fs.writeFileSync(__dirname+'/results.json',JSON.stringify(result,null,2)+'\n'); console.log(JSON.stringify(result,null,2));