@casadi/casadi-viz 0.1.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +165 -0
- package/NOTICE +3 -0
- package/README.md +169 -0
- package/dist/casadi-viz.global.js +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +24 -0
- package/dist/licenses/viz-package.json +44 -0
- package/dist/licenses/viz-provenance.json +2106 -0
- package/dist/standalone.html +33 -0
- package/dist/viz-global.js +9 -0
- package/package.json +46 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CasADi graph</title>
|
|
3
|
+
<style>html,body{height:100%;margin:0}#graph{display:block;height:100%}</style></head><body><div id="graph"></div>
|
|
4
|
+
<script id="graph-data" type="application/json">@@GRAPH_DATA@@</script>
|
|
5
|
+
<script id="viz-config" type="application/json">@@VIZ_CONFIG@@</script>
|
|
6
|
+
<script>const __casadiVizScriptURL=document.currentScript?.src || document.baseURI;
|
|
7
|
+
var CasadiViz=(()=>{var he=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var Me=Object.prototype.hasOwnProperty;var Ie=(E,N)=>{for(var R in N)he(E,R,{get:N[R],enumerable:!0})},je=(E,N,R,g)=>{if(N&&typeof N=="object"||typeof N=="function")for(let L of Be(N))!Me.call(E,L)&&L!==R&&he(E,L,{get:()=>N[L],enumerable:!(g=De(N,L))||g.enumerable});return E};var Pe=E=>je(he({},"__esModule",{value:!0}),E);var $e={};Ie($e,{createGraphViewer:()=>Ge});var Ee=`
|
|
8
|
+
:host{font:14px Arial,Helvetica,sans-serif;color:#222;background:white;--accent:#b00000;--blue:#34658b;--line:#e8e8e8}
|
|
9
|
+
*{box-sizing:border-box}[hidden]{display:none!important}.viewer{margin:0;height:100%;display:flex;flex-direction:column}
|
|
10
|
+
header{padding:16px 24px;border-bottom:1px solid var(--line);display:flex;gap:20px;align-items:center;justify-content:space-between;flex-wrap:wrap}
|
|
11
|
+
.brand{font-size:19px;font-weight:700;letter-spacing:-.04em}.brand span{color:var(--accent)}h1{font-size:18px;margin:0;font-weight:400}#meta{color:#888;font-size:12px;margin-top:5px}.identity{display:flex;gap:24px;align-items:center;min-width:0}#breadcrumbs{display:flex;gap:7px;align-items:center;flex-wrap:wrap}#breadcrumbs button{border:0;padding:2px 0;font-size:17px;color:#34658b;background:none}#breadcrumbs button:disabled{opacity:1;color:#222;cursor:default}#breadcrumbs span{color:#aaa}.toggle{display:flex;align-items:center;gap:7px;font-size:12px;cursor:pointer;white-space:nowrap}.toggle input{appearance:none;position:relative;width:28px;height:16px;border-radius:12px;background:#ccc;margin:0;cursor:pointer;flex-shrink:0}.toggle input:checked{background:var(--accent)}.toggle input::after{content:"";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:white;transition:transform .12s}.toggle input:checked::after{transform:translateX(12px)}.toggle input:focus-visible{outline:2px solid #34658b;outline-offset:2px}
|
|
12
|
+
button,.upload{font:inherit;background:white;border:1px solid #ddd;border-radius:4px;padding:7px 11px;cursor:pointer;white-space:nowrap;color:inherit}button:hover,.upload:hover{background:#f6f6f6}button:disabled{opacity:.35;cursor:default}button[aria-pressed=true]{border-color:var(--accent);color:var(--accent);background:#fff6f6}.upload{display:inline-block}.upload:focus-within{outline:2px solid var(--blue)}.upload input{position:absolute;width:1px;height:1px;opacity:0}
|
|
13
|
+
#toolbar{display:flex;gap:8px;align-items:center;padding:10px 24px;border-bottom:1px solid var(--line);flex-wrap:wrap;background:#fafafa}#timeline{flex:1;min-width:100px;accent-color:var(--accent)}#step-label{min-width:100px;font-variant-numeric:tabular-nums;color:#777;font-size:12px}select{font:inherit;border:1px solid #ddd;border-radius:4px;padding:6px;background:white}
|
|
14
|
+
main{display:flex;flex:1;min-height:0}#canvas{flex:1;position:relative;overflow:hidden;background:white}#canvas svg{width:100%;height:100%;display:block;touch-action:none}#canvas .node,#canvas .io-node,#canvas .value-node{cursor:pointer}#canvas .node text,#canvas .io-node text,#canvas .value-node text{pointer-events:none}#canvas .io-node.active>ellipse,#canvas .node.active>ellipse,#canvas .node.active>polygon,#canvas .node.active>path{stroke:#222;stroke-width:2.5}#canvas .io-node.executed>ellipse,#canvas .node.executed>ellipse,#canvas .node.executed>polygon,#canvas .node.executed>path{stroke:var(--blue);stroke-width:2.5}#canvas .node.failed>ellipse,#canvas .node.failed>polygon,#canvas .node.failed>path{stroke:#e18c24;stroke-width:3}#canvas .value-node.active>polygon{stroke:var(--blue);stroke-width:1.5}#canvas .trace-value{font:11px ui-monospace,monospace;fill:var(--blue);paint-order:stroke;stroke:white;stroke-width:4px;stroke-linejoin:round}#canvas .edge path{stroke:var(--blue)}#canvas .edge polygon{fill:var(--blue);stroke:var(--blue)}
|
|
15
|
+
#loading{position:absolute;inset:0;display:grid;place-content:center;text-align:center;color:#777;gap:12px;background:#fffffff2}#loading p{max-width:420px;margin:0;padding:0 20px}#loading button{justify-self:center}
|
|
16
|
+
aside{width:340px;max-width:42vw;background:white;border-left:1px solid var(--line);padding:20px;overflow:auto}.selection-header{display:flex;align-items:center;justify-content:space-between;gap:12px}aside h2{font-size:18px;font-weight:400;margin:0}aside h3{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:#888;margin:22px 0 8px}#close-inspector{border:0;font-size:20px;padding:0 5px}pre{font:12px/1.6 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;background:#f7f7f7;padding:10px;margin:14px 0 0}.hint{font-size:12px;line-height:1.6;color:#888}.port{border-top:1px solid #eee;padding:10px 0}.port-title{font:12px ui-monospace,monospace;color:#666;margin-bottom:8px}.port-value{font:12px/1.5 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.matrix{border-collapse:collapse;margin:8px 0;font:11px ui-monospace,monospace}.matrix td{border:1px solid #ddd;padding:5px;text-align:center;white-space:nowrap}.matrix td.nz{background:#eee}.matrix td.zero{color:#aaa}.matrix td.spy{width:16px;height:16px;padding:3px;background:white;border:0}.matrix td.nz.spy::after{content:"";display:block;background:#111;width:9px;height:9px}.matrix:has(.spy){border:1px solid #ddd}.matrix-wrap{overflow:auto}.state{font-size:12px;color:var(--blue);margin:14px 0}details{font-size:12px;color:#666;margin-top:10px}summary{cursor:pointer}
|
|
17
|
+
footer{padding:8px 24px;border-top:1px solid var(--line);display:flex;justify-content:space-between;gap:16px;font-size:11px;color:#888}#status.error{color:#b00000}#status.warning{color:#936015}#trace-name{max-width:50%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.right-tools{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.legend{display:flex;gap:14px;align-items:center}.legend span::before{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:5px;background:var(--accent)}.legend .symbol::before{background:#34658b}.legend .constant::before{background:#38754d}
|
|
18
|
+
@media(max-width:700px){header{padding:12px}.identity{gap:12px}.brand{font-size:16px}#toolbar{padding:10px}aside{width:240px;padding:12px}footer{padding:8px}}
|
|
19
|
+
`;var Le=`<div class="viewer">
|
|
20
|
+
<header><div class="identity"><div class="brand">Cas<span>AD</span>i</div><div><nav id="breadcrumbs" aria-label="Function navigation"></nav><div id="meta"></div></div></div><div class="right-tools"><select id="view-mode" aria-label="Graph view"><option value="expression">Expression view</option><option value="function">Function view</option></select><label class="toggle"><input id="detail-toggle" type="checkbox" role="switch" checked>Show matrix contents</label><label class="toggle"><input id="size-toggle" type="checkbox" role="switch" checked>Show matrix sizes</label><button id="fit">Fit graph</button><button id="trace-toggle" aria-pressed="false" aria-controls="toolbar">Trace</button></div></header>
|
|
21
|
+
<div id="toolbar" hidden><label class="upload">Load trace<input id="trace-file" type="file" accept=".jsonl,.json,.txt" aria-label="Load evaluation trace"></label><button id="start" title="Rewind" disabled>↤</button><button id="back" title="Previous instruction" disabled>←</button><button id="play" disabled>Play</button><button id="next" title="Next instruction" disabled>→</button><button id="end" title="Last instruction" disabled>↦</button><input id="timeline" type="range" min="0" max="0" value="0" disabled aria-label="Evaluation position"><span id="step-label">No trace loaded</span><select id="speed" aria-label="Playback speed"><option value="800">Slow</option><option value="350" selected>Normal</option><option value="80">Fast</option></select></div>
|
|
22
|
+
<main><div id="canvas"><div id="loading"><p id="loading-text">Laying out the graph…</p><button id="cancel-layout">Cancel layout</button></div></div><aside id="details" hidden><div class="selection-header"><h2 id="selection-title"></h2><button id="close-inspector" aria-label="Close inspector">×</button></div><div id="inspector"></div></aside></main>
|
|
23
|
+
<footer><span id="status" role="status">Preparing graph…</span><div class="right-tools"><span id="trace-name" hidden></span><div class="legend" aria-label="Node colors"><span class="symbol">Symbols</span><span class="constant">Constants</span><span>Operations</span></div></div></footer>
|
|
24
|
+
</div>`;function Te(E){if(!E||E.format!=="casadi_viz"||E.version!==1)throw new Error("Expected a casadi_viz bundle (version 1)");if(!Array.isArray(E.functions))throw Error("Expected a functions array");let N=[E,...E.functions];for(let R of N){for(let g of["nodes","edges","inputs","outputs"])if(!Array.isArray(R[g]))throw Error("Missing graph array: "+g);R.nodes.forEach((g,L)=>{if(g.id!==L)throw Error("Instruction IDs must be consecutive");if(g.callee!==void 0&&(!Number.isInteger(g.callee)||!N[g.callee]))throw Error("Invalid callee reference");for(let V of["inputs","outputs","input_names","output_names","constants"])if(!Array.isArray(g[V]))throw Error("Missing instruction array: "+V)});for(let g of R.edges)if(!Number.isInteger(g.from)||!Number.isInteger(g.to)||!R.nodes[g.from]||!R.nodes[g.to]||!Number.isInteger(g.input)||!Number.isInteger(g.output)||g.input<0||g.input>=R.nodes[g.to].inputs.length||g.output<0||g.output>=R.nodes[g.from].outputs.length)throw Error("Invalid dependency edge")}return E}function Ge(E,N={}){if(!E||typeof E.attachShadow!="function")throw new TypeError("Expected a host element");let R=E.shadowRoot||E.attachShadow({mode:"open"}),g=N.runtime||{url:new URL("./viz-global.js",__casadiVizScriptURL).href},L=null,V=!1;return{async setGraph($){if(V)throw Error("Viewer has been destroyed");let z=Te(typeof $=="string"?JSON.parse($):$);return L?.destroy(),R.innerHTML="<style>"+Ee+"</style>"+Le,L=Ve(R,z,g),L.ready},async loadTrace($){if(!L||V)throw Error("Load a graph before loading a trace");return L.loadTrace($)},setView($){if(!L||V)throw Error("Load a graph before selecting a view");L.setView($)},destroy(){L?.destroy(),L=null,V=!0,R.replaceChildren()}}}function Ve(E,N,R){let g,L,V=new Promise((e,i)=>{g=e,L=i}),$=[N,...N.functions||[]],z=N,l=e=>E.querySelector("#"+e),W=(e,i="")=>{l("status").textContent=e,l("status").className=i},w=null,me=null,f=null,y=0,A=null,te=null,j=!1,le=!0,ue=!0,G=N.view||"function",P=[{model:z,viewMode:G,trace:null,cursor:0,selected:null,traceName:""}],Q=new Map,X=new Map,ne=null,ge=e=>typeof e=="number"?Object.is(e,-0)?"-0":Number(e.toPrecision(7)).toString():e,be=e=>e.map(i=>i===null?"unused":"["+i.slice(0,3).map(ge).join(", ")+(i.length>3?", \u2026":"")+"]").join(" ; ");function B(){clearInterval(te),te=null,l("play").textContent="Play"}function pe(){let e=f?f.count:0;l("start").disabled=l("back").disabled=!f||y===0,l("next").disabled=l("end").disabled=!f||y===e,l("play").disabled=!f||e===0,l("timeline").disabled=!f,l("timeline").max=e,l("timeline").value=y,l("step-label").textContent=f?`${y.toLocaleString()} / ${e.toLocaleString()}`:"No trace loaded"}function xe(e,i,s,r,d=!1){let t=document.createElement("section"),c=document.createElement("h3");if(c.textContent=e,t.append(c),!i.length){let o=document.createElement("div");o.className="hint",o.textContent="None",t.append(o)}return i.forEach((o,u)=>{let p=document.createElement("div");p.className="port";let b=document.createElement("div");b.className="port-title",b.textContent=`${r[u]}${ue?" \xB7 "+o.shape.join("-by-"):""} \xB7 ${o.row.length} nonzeros`;let k=document.createElement("div");if(k.className="port-value",k.textContent=s===void 0?j?"Not evaluated":"":s[u]===null?"Unused / absent buffer":"["+s[u].map(M=>Object.is(M,-0)?"-0":String(M)).join(", ")+"]",p.append(b,k),le&&o.shape[0]*o.shape[1]!==1&&p.append(Ce(o,s?.[u],d)),o.row.length!==o.shape[0]*o.shape[1]){let M=document.createElement("details"),T=document.createElement("summary"),I=document.createElement("pre");T.textContent="Sparsity",I.textContent="colind: "+JSON.stringify(o.colind)+`
|
|
25
|
+
row: `+JSON.stringify(o.row),M.append(T,I),p.append(M)}t.append(p)}),t}function Ce(e,i,s){let r=document.createElement("div");r.className="matrix-wrap";let d=document.createElement("table");d.className="matrix";let t=new Map;for(let c=0;c<Math.min(8,e.shape[1]);c++)for(let o=e.colind[c];o<e.colind[c+1];o++)e.row[o]<8&&t.set(e.row[o]+","+c,o);for(let c=0;c<Math.min(8,e.shape[0]);c++){let o=d.insertRow();for(let u=0;u<Math.min(8,e.shape[1]);u++){let p=o.insertCell(),b=t.get(c+","+u);p.className=b===void 0?"zero":"nz",s||p.classList.add("spy"),p.textContent=s?b===void 0?".":String(i[b]):"",p.title=b===void 0?"Structural zero":`Row ${c}, column ${u}, nonzero ${b}`}}if(r.append(d),e.shape.some(c=>c>8)){let c=document.createElement("div");c.className="hint",c.textContent="Showing the first 8 rows / columns. Full sparsity below.",r.append(c)}return r}function U(){if(A===null)return;let e=z.nodes[A],i=j&&f&&A<y;l("selection-title").textContent=G==="expression"&&e.kind==="input"?e.symbol:G==="function"&&["input","output"].includes(e.kind)?z[e.kind+"s"][e.io_index].name:e.display;let s=l("inspector");if(s.replaceChildren(),j){let o=document.createElement("div");o.className="state",o.textContent=i?f.after[A]===void 0?"Interrupted":"Evaluated":"Not evaluated",s.append(o)}let r=document.createElement("pre");if(r.textContent=e.formula,e.callee!==void 0){let o=document.createElement("button");o.id="enter-function",o.textContent="Step into "+e.display,o.onclick=()=>ke(e.id),s.append(o)}else if(e.kind==="call"){let o=document.createElement("p");o.className="hint",o.textContent="No internal graph was included for this "+e.callee_type+".",s.append(o)}if(s.append(r,xe("Inputs",e.inputs,i?f.before[A]:void 0,e.input_names),xe("Outputs",e.outputs,i?f.after[A]:e.kind==="constant"?[e.constants]:void 0,e.output_names,e.kind==="constant")),e.mapping){let o=document.createElement("h3"),u=document.createElement("pre");o.textContent="Nonzero mapping",u.textContent=e.mapping.map((p,b)=>`${b}: ${p}`).join(", "),s.append(o,u)}let d=document.createElement("details"),t=document.createElement("summary"),c=document.createElement("pre");t.textContent="Evaluator expression",c.textContent=e.expression,d.append(t,c),s.append(d)}function oe(e){if(A!==null){Q.get(A)?.classList.remove("active");for(let i of X.get(A)||[])i.element.classList.remove("active")}A=e,Q.get(e)?.classList.add("active");for(let i of X.get(e)||[])i.element.classList.add("active");l("details").hidden=!1,U()}l("close-inspector").onclick=()=>{Q.get(A)?.classList.remove("active");for(let e of X.get(A)||[])e.element.classList.remove("active");A=null,l("details").hidden=!0};function ie(e){let i=Q.get(e),s=j&&f&&e<y,r=s&&f.after[e]!==void 0;i?.classList.toggle("executed",!!r),i?.classList.toggle("failed",!!s&&!r);let d=i?.querySelector(".trace-value");if(i&&!d){d=document.createElementNS("http://www.w3.org/2000/svg","text"),d.classList.add("trace-value");let o=i.getBBox();d.setAttribute("x",o.x+o.width/2),d.setAttribute("y",o.y+o.height+14),d.setAttribute("text-anchor","middle"),i.append(d)}let t=s?z.nodes[e].kind==="output"?f.before[e]:f.after[e]:void 0,c=t===void 0?"":be(t);d&&(d.textContent=c.length>36?c.slice(0,35)+"\u2026":c);for(let o of X.get(e)||[]){if(o.boundary){Se(o.boundary);continue}let u=t?.[o.port];for(let p of o.cells)p.element.textContent=le&&u?ge(u[p.index]):p.label}}function Se(e){let i=Array(Math.min(4,e.sp.row.length)).fill("?"),s=!1;for(let r of e.owners){if(!j||!f||r.node>=y)continue;let d=(e.boundaryKind==="input"?f.after[r.node]:f.before[r.node])?.[0];if(d){s=!0;for(let t=0;t<d.length&&r.offset+t<i.length;t++)i[r.offset+t]=d[t]}}e.traceLabel.textContent=s?be([i]):"",e.traceLabel.parentNode.classList.toggle("executed",!!s&&e.owners.every(r=>r.node<y&&f.after[r.node]!==void 0))}l("trace-toggle").onclick=()=>{j=!j,B(),l("trace-toggle").setAttribute("aria-pressed",String(j)),l("toolbar").hidden=!j,l("trace-name").hidden=!j;for(let e=0;e<y;e++)ie(e);U(),W(j?f?"Trace loaded. Step through the evaluation.":"Load a trace file to replay an evaluation. Files stay in your browser.":"Select a node to inspect it. Scroll to zoom; drag to pan.")};function Y(e,i=!0){let s=y;y=Math.max(0,Math.min(f?f.count:0,e));for(let r=Math.min(s,y);r<Math.max(s,y);r++)ie(r);if(i&&y>0){let r=y-1;G==="expression"&&z.nodes[r].kind==="output"&&(r=z.edges.find(d=>d.to===r)?.from??r),oe(r)}else U();pe(),f&&y===f.count&&B()}l("start").onclick=()=>{B(),Y(0)},l("back").onclick=()=>{B(),Y(y-1)},l("next").onclick=()=>{B(),Y(y+1)},l("end").onclick=()=>{B(),Y(f.count)},l("timeline").oninput=()=>{B(),Y(Number(l("timeline").value))},l("play").onclick=()=>{if(te){B();return}y===f.count&&Y(0),l("play").textContent="Pause",te=setInterval(()=>Y(y+1),Number(l("speed").value))},l("speed").onchange=()=>{te&&(B(),l("play").click())};function ce(e,i,s){if(!Array.isArray(e)||e.length!==i.length)throw Error(s+": wrong number of values");e.forEach((r,d)=>{if(r!==null){if(!Array.isArray(r)||r.length!==i[d].row.length)throw Error(s+": nonzero count does not match the graph");for(let t of r)if(!(typeof t=="number"&&Number.isFinite(t))&&!["nan","inf","-inf"].includes(t))throw Error(s+": invalid numerical value")}})}async function Ne(e,i=z){let s={before:[],after:[],count:0,ended:!1,status:null},r=!1,d=!1,t=!1,c=!1,o=!1,u=0,p=0;function b(I){if(!I.trim())return;p++;let m=JSON.parse(I);if(!m||typeof m!="object"||Array.isArray(m))throw Error("Expected a trace record");if(c)throw Error("Unexpected data after trace end");if(!r){if(m.event!=="header"||m.format!=="casadi_trace"||m.version!==1)throw Error("Expected a dump_trace JSONL file (version 1)");if(m.function!==i.name||m.type!==i.type)throw Error("This trace belongs to a different function");r=!0;return}if(!d){if(m.event!=="inputs")throw Error("Missing function inputs");ce(m.values,i.inputs.map(_=>_.sparsity),"Function inputs"),d=!0;return}if(m.event==="error"){c=!0,s.status="error";return}if(m.event==="outputs"){if(o||u!==i.nodes.length||t)throw Error("Unexpected function outputs");ce(m.values,i.outputs.map(_=>_.sparsity),"Function outputs"),t=!0;return}if(m.event==="end"){if(!Number.isInteger(m.status))throw Error("Invalid evaluation status");if(m.status===0&&(!t||o||u!==i.nodes.length))throw Error("Successful trace is missing instructions");s.ended=!0,s.status=m.status,c=!0;return}let O=m.instruction;if(t||!Number.isInteger(O)||O!==u||O>=i.nodes.length||m.op!==i.nodes[O].op)throw Error("Instruction sequence does not match this graph");if(m.phase==="inputs"&&!o)ce(m.values,i.nodes[O].inputs,"Instruction "+O+" inputs"),s.before[O]=m.values,s.count=O+1,o=!0;else if(m.phase==="outputs"&&o)ce(m.values,i.nodes[O].outputs,"Instruction "+O+" outputs"),s.after[O]=m.values,o=!1,u++;else throw Error("Unexpected instruction phase")}let k=e.stream().getReader(),M=new TextDecoder,T="";try{for(;;){let{done:I,value:m}=await k.read();if(I)break;T+=M.decode(m,{stream:!0});let O=0,_;for(;(_=T.indexOf(`
|
|
26
|
+
`,O))!==-1;)b(T.slice(O,_)),O=_+1;T=T.slice(O)}if(T+=M.decode(),T.trim()&&b(T),!r||!d)throw Error("Incomplete trace header")}catch(I){throw await k.cancel(),Error(`Line ${p}: ${I.message}`)}finally{k.releaseLock()}return s}let re=0;async function we(e){if(typeof e=="string"&&(e=new File([e],"evaluation.trace.jsonl")),!e)return;let i=++re;B(),W("Reading trace\u2026");try{let s=await Ne(e);if(i!==re)return;let r=y;f=s,y=0;for(let d=0;d<r;d++)ie(d);pe(),U(),l("trace-name").textContent=e.name,W(s.ended&&s.status===0?"Trace loaded. Step through the evaluation.":"Partial or failed evaluation. Recorded instructions are available.",s.ended&&s.status===0?"":"warning")}catch(s){throw i===re&&W(s.message,"error"),s}l("trace-file").value=""}l("trace-file").onchange=()=>we(l("trace-file").files[0]).catch(()=>{});function fe(){l("view-mode").value=G;let e=l("breadcrumbs");e.replaceChildren(),P.forEach((i,s)=>{if(s){let d=document.createElement("span");d.textContent="/",e.append(d)}let r=document.createElement("button");r.textContent=i.model.name,r.disabled=s===P.length-1,r.disabled&&(r.id="name",r.setAttribute("aria-current","page")),r.onclick=()=>Re(s),e.append(r)}),l("meta").textContent=`${z.type} \xB7 ${z.nodes.length.toLocaleString()} instructions \xB7 ${z.edges.length.toLocaleString()} connections`}function ve(){Object.assign(P[P.length-1],{viewMode:G,trace:f,cursor:y,selected:A,traceName:l("trace-name").textContent})}function ye(){B(),++re,{model:z,viewMode:G,trace:f,cursor:y,selected:A}=P[P.length-1],l("trace-name").textContent=P[P.length-1].traceName,l("details").hidden=A===null,fe(),pe(),U(),ee(),W(f?"Trace restored. Step through the evaluation.":"Select a node to inspect it. Double-click a function to step inside.")}function ke(e){let i=z.nodes[e].callee;i!==void 0&&(ve(),P.push({model:$[i],viewMode:"function",trace:null,cursor:0,selected:null,traceName:""}),ye())}function Re(e){ve(),P=P.slice(0,e+1),ye()}function Ae(){self.onmessage=async({data:e})=>{try{let I=function(n,a,x){let q="value-"+n.id+"-"+x,H=[],J=new Map;for(let C=0;C<Math.min(8,a.shape[1]);C++)for(let S=a.colind[C];S<a.colind[C+1];S++)a.row[S]<8&&J.set(a.row[S]+","+C,S);let D=Math.max(1,Math.min(8,a.shape[1])),v='<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="3" COLOR="#cccccc">',h=[n.boundary?n.display:n.kind==="call"?n.output_names[x]:"",e.showSizes?a.shape.join("-by-"):""].filter(Boolean).join(" : ");h&&(v+='<TR><TD COLSPAN="'+D+'" BGCOLOR="white"><FONT COLOR="'+(n.role==="input"?"#34658b":n.role==="output"?"#b00000":"#666666")+'">'+s(h)+"</FONT></TD></TR>");for(let C=0;C<Math.min(8,a.shape[0]);C++){v+="<TR>";for(let S=0;S<Math.min(8,a.shape[1]);S++){let F=J.get(C+","+S),Z=n.kind==="constant"?F===void 0?".":n.constants[F]:"";F!==void 0&&H.push({label:Z,index:F}),v+="<TD"+(F===void 0?"":' PORT="nz'+F+'"')+' BGCOLOR="white">',n.kind==="constant"?v+=s(Z):v+='<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="0"><TR><TD FIXEDSIZE="TRUE" WIDTH="9" HEIGHT="9" BGCOLOR="'+(F===void 0?"white":"#111111")+'"></TD></TR></TABLE>',v+="</TD>"}a.shape[1]===0&&(v+="<TD>empty</TD>"),v+="</TR>"}return a.shape.some(C=>C>8)&&(v+='<TR><TD COLSPAN="'+D+'">...</TD></TR>'),!h&&!a.shape[0]&&(v+="<TR><TD>empty</TD></TR>"),v+="</TABLE>",T.push("v"+n.id+"_"+x+' [id="'+q+'", shape=plain, fontcolor="#666666", fontsize=10, label=<'+v+">];"),n.boundary||T.push("n"+n.id+(n.kind==="call"?":out"+x:"")+" -> v"+n.id+"_"+x+" [arrowsize=0.5];"),t.set(n.id+":"+x,"v"+n.id+"_"+x),d.push({id:q,node:n.id,port:x,cells:H}),d[d.length-1]};e.url&&importScripts(e.url);let i=n=>JSON.stringify(n),s=n=>String(n).replace(/[&<>"]/g,a=>({"&":"&","<":"<",">":">",'"':"""})[a]),r=e.model,d=[],t=new Map,c=new Map,o=new Set,u=n=>n.shape[0]*n.shape[1]!==1,p=(n,a)=>u(a)&&(n.kind==="call"||n.mapping||!n.inputs.length||!n.inputs.every(x=>JSON.stringify(x)===JSON.stringify(a))),b=n=>n.ordered&&!n.binary||n.kind==="call",k=e.viewMode==="function",M=k?"TB":r.direction;for(let n of r.nodes)(n.kind==="output"||k&&n.kind==="input")&&o.add(n.id);let T=["digraph G {","graph [rankdir="+M+', bgcolor="white", pad="0.4", nodesep="0.55", ranksep="0.65"];','node [shape=ellipse, style=filled, color="#b00000", fillcolor="#b00000", fontcolor="white", fontname="Helvetica", fontsize=14, margin="0.15,0.08", width=0.5, height=0.5];','edge [color="#34658b", penwidth=1.5, arrowsize=0.65];'];for(let n of r.nodes){let a=!k&&n.kind==="input"?{...n,display:n.symbol}:n;if(o.has(a.id))continue;let x=a.outputs[0]||a.inputs[0],q=e.showSizes&&x&&u(x)&&!(e.showContents&&a.outputs.some(v=>p(a,v)))?`
|
|
27
|
+
`+x.shape.join("-by-"):"",H=i(a.display+q),J="ellipse";if(b(a)){J="plain";let v=(C,S)=>"<TR>"+C.map((F,Z)=>'<TD PORT="'+S+Z+'"><FONT POINT-SIZE="10">'+s(F+(e.showSizes&&(S==="in"?a.inputs:a.outputs)[Z]&&u((S==="in"?a.inputs:a.outputs)[Z])?" "+(S==="in"?a.inputs:a.outputs)[Z].shape.join("-by-"):""))+"</FONT></TD>").join("")+"</TR>",h='<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="6" BGCOLOR="#b00000">';a.input_names.length&&(h+='<TR><TD><TABLE BORDER="0" CELLBORDER="1" COLOR="#d26666" CELLSPACING="0">'+v(a.input_names,"in")+"</TABLE></TD></TR>"),h+="<TR><TD>"+s(a.display)+"</TD></TR>",a.kind==="call"&&a.output_names.length&&(h+='<TR><TD><TABLE BORDER="0" CELLBORDER="1" COLOR="#d26666" CELLSPACING="0">'+v(a.output_names,"out")+"</TABLE></TD></TR>"),H="<"+h+"</TABLE>>"}let D=a.kind==="input"||a.kind==="symbol"?"#34658b":a.kind==="constant"?"#38754d":"#b00000";T.push("n"+a.id+' [id="instruction-'+a.id+'", shape='+J+", color="+i(D)+", fillcolor="+i(D)+", label="+H+"];"),a.outputs.forEach((v,h)=>{e.showContents&&p(a,v)&&I(a,v,h)})}let m={input:[],output:[]};for(let n of["input","output"])r[n+"s"].forEach((a,x)=>{let q=!k&&n==="output"&&r.type==="SXFunction"&&e.showContents&&u(a.sparsity);if(!k&&!q)return;let H={id:"boundary_"+n+"_"+x,kind:"boundary",boundary:!0,role:k?n:"",display:k?a.name:""},J=r.nodes.filter(h=>h.kind===n&&h.io_index===x).map(h=>({node:h.id,offset:h.io_offset,count:(n==="input"?h.outputs:h.inputs)[0].row.length})),D,v;if(e.showContents&&u(a.sparsity))D=I(H,a.sparsity,0),v="v"+H.id+"_0",D.cells=D.cells.flatMap(h=>{let C=J.find(S=>h.index>=S.offset&&h.index<S.offset+S.count);return C?[{...h,node:C.node,index:h.index-C.offset}]:[]});else{v="b"+n+"_"+x;let h=n==="input"?"#34658b":"#b00000",C=a.name+(e.showSizes&&u(a.sparsity)?`
|
|
28
|
+
`+a.sparsity.shape.join("-by-"):"");T.push(v+' [id="boundary-'+n+"-"+x+'", label='+i(C)+", color="+i(h)+", fillcolor="+i(h)+"];"),D={id:"boundary-"+n+"-"+x,node:null,port:0,cells:[],render:"io"},d.push(D)}Object.assign(D,{node:null,boundary:!0,boundaryKind:n,sp:a.sparsity,owners:J});for(let h of J){let C=D.cells.some(F=>F.node===h.node),S=v+(r.type==="SXFunction"&&C?":nz"+h.offset:"");n==="input"?t.set(h.node+":0",S):c.set(h.node,S)}k&&m[n].push(v)});if(k)for(let n of["input","output"]){let a=m[n];if(a.length){T.push("{ rank="+(n==="input"?"source":"sink")+"; "+a.join("; ")+"; }");for(let x=1;x<a.length;x++)T.push(a[x-1]+" -> "+a[x]+" [style=invis, weight=100];")}}for(let n of r.edges){if(o.has(n.to)&&!c.has(n.to))continue;let a=t.get(n.from+":"+n.output)||"n"+n.from+(r.nodes[n.from].kind==="call"?":out"+n.output:""),x=r.nodes[n.to],q=c.get(n.to)||"n"+n.to+(b(x)?":in"+n.input:"");x.binary&&(q+=n.input===0?":w":":e"),T.push(a+" -> "+q+";")}T.push("}");let O=await Viz.instance(),_=O.render(T.join(`
|
|
29
|
+
`),{engine:"dot",format:"svg"});if(_.status!=="success")throw Error(_.errors.map(n=>n.message).join("; "));self.postMessage({svg:_.output,details:d,hidden:Array.from(o)})}catch(i){self.postMessage({error:i.message||String(i)})}}}let Oe="("+Ae.toString()+")();",K=null,ae=null;function de(){K&&K.terminate(),K=null,ae&&URL.revokeObjectURL(ae),ae=null}function se(e){L(new Error(e)),de(),l("loading-text").textContent=e,l("cancel-layout").hidden=!0,W(e,"error")}function ze(e,i,s){let r=new DOMParser().parseFromString(e,"image/svg+xml");if(r.querySelector("parsererror")||r.documentElement.localName!=="svg")throw Error("Viz.js returned invalid SVG");w=document.importNode(r.documentElement,!0),w.setAttribute("role","img"),w.setAttribute("aria-label","Function instruction graph"),w.removeAttribute("width"),w.removeAttribute("height"),l("canvas").prepend(w),me=w.getAttribute("viewBox");for(let t of i){let c=w.getElementById(t.id);c.classList.remove("node"),c.classList.add(t.render==="io"?"io-node":"value-node"),c.onclick=()=>{let p=t.node??t.cells[0]?.node??t.owners?.[0]?.node;p!==void 0&&oe(p)};let o=Array.from(c.querySelectorAll("text")),u=new Map;if(t.boundary){for(let k of t.owners)u.set(k.node,[]);let p=document.createElementNS("http://www.w3.org/2000/svg","text"),b=c.getBBox();p.classList.add("trace-value"),p.setAttribute("x",b.x+b.width/2),p.setAttribute("y",b.y+b.height+14),p.setAttribute("text-anchor","middle"),c.append(p),t.traceLabel=p}for(let p of t.cells){let b=o.findIndex(M=>M.textContent===p.label),k=p.node??t.node;u.has(k)||u.set(k,[]),b>=0&&u.get(k).push({...p,element:o.splice(b,1)[0]})}t.node!==null&&!u.has(t.node)&&u.set(t.node,[]);for(let[p,b]of u)X.has(p)||X.set(p,[]),X.get(p).push({element:c,port:t.port,cells:b,boundary:t.boundary?t:null})}for(let t of z.nodes){let c=w.getElementById("instruction-"+t.id);if(!c){if(s.includes(t.id)){ie(t.id);continue}throw Error("Missing graph node "+t.id)}Q.set(t.id,c),c.onclick=()=>oe(t.id),t.callee!==void 0&&(c.onclick=()=>{clearTimeout(ne),ne=setTimeout(()=>oe(t.id),400)},c.ondblclick=()=>{clearTimeout(ne),ke(t.id)},c.querySelector("title").textContent="Double-click to step into "+t.display),ie(t.id)}A!==null&&oe(A),w.addEventListener("wheel",t=>{t.preventDefault();let c=w.viewBox.baseVal,o=Math.exp(Math.max(-1,Math.min(1,t.deltaY*.001))),u=new DOMPoint(t.clientX,t.clientY).matrixTransform(w.getScreenCTM().inverse());w.setAttribute("viewBox",[u.x+(c.x-u.x)*o,u.y+(c.y-u.y)*o,c.width*o,c.height*o].join(" "))},{passive:!1});let d=null;w.onpointerdown=t=>{t.button!==0||t.target.closest(".node,.io-node,.value-node")||(d={x:t.clientX,y:t.clientY,view:w.getAttribute("viewBox").split(/\s+/).map(Number)},w.setPointerCapture(t.pointerId))},w.onpointermove=t=>{if(!d)return;let c=w.getScreenCTM(),[o,u,p,b]=d.view;w.setAttribute("viewBox",[o-(t.clientX-d.x)/c.a,u-(t.clientY-d.y)/c.d,p,b].join(" "))},w.onpointerup=w.onpointercancel=()=>{d=null},g(),l("loading").hidden=!0,f||W("Select a node to inspect it. Scroll to zoom; drag to pan.")}l("fit").onclick=()=>{w&&w.setAttribute("viewBox",me)},l("cancel-layout").onclick=()=>se("Layout cancelled. Reopen the file to try again.");function ee(){clearTimeout(ne),de(),w&&w.remove(),w=null,Q.clear(),X.clear(),l("loading").hidden=!1,l("loading-text").textContent="Laying out the graph\u2026",l("cancel-layout").hidden=!1;try{ae=URL.createObjectURL(new Blob([R.source||"",`
|
|
30
|
+
`,Oe],{type:"text/javascript"})),K=new Worker(ae),K.onmessage=({data:e})=>{if(e.error){se("Layout failed: "+e.error);return}de();try{ze(e.svg,e.details,e.hidden)}catch(i){se(i.message)}},K.onerror=e=>se("Could not load Viz.js. Check connectivity, or export with the viz_js option for offline use."),K.postMessage({url:R.url,model:z,viewMode:G,showContents:le,showSizes:ue})}catch(e){se(e.message)}}return l("view-mode").onchange=()=>{G=l("view-mode").value,U(),ee()},l("detail-toggle").onchange=()=>{le=l("detail-toggle").checked,U(),ee()},l("size-toggle").onchange=()=>{ue=l("size-toggle").checked,U(),ee()},fe(),ee(),{ready:V,loadTrace:we,destroy(){B(),clearTimeout(ne),++re,de(),L(new DOMException("Viewer replaced or destroyed","AbortError"))},setView(e){if(!["function","expression"].includes(e))throw Error("Unknown graph view: "+e);G=e,fe(),U(),ee()}}}return Pe($e);})();
|
|
31
|
+
</script>
|
|
32
|
+
<script>const viewer=CasadiViz.createGraphViewer(document.getElementById('graph'),{runtime:JSON.parse(document.getElementById('viz-config').textContent)});viewer.setGraph(JSON.parse(document.getElementById('graph-data').textContent)).catch(console.error);</script>
|
|
33
|
+
</body></html>
|