/* Force-directed and Embedding (UMAP) layouts for the prerequisite graph. Same node set as PrerequisiteGraph hierarchical for comparability. */ const _GRAPH_NODES = [ { id:"real_numbers", label:"ℝ", kind:"axiom", mastery:"mastered" }, { id:"set", label:"Set", kind:"definition", mastery:"mastered" }, { id:"function", label:"Function", kind:"definition", mastery:"mastered" }, { id:"interval", label:"Open interval", kind:"definition", mastery:"mastered" }, { id:"sequence", label:"Sequence", kind:"definition", mastery:"mastered" }, { id:"slope_line", label:"Slope of a line", kind:"definition", mastery:"learning" }, { id:"absolute_val", label:"Absolute value", kind:"definition", mastery:"mastered" }, { id:"composition", label:"Composition", kind:"definition", mastery:"mastered" }, { id:"limit_seq", label:"Limit · seq", kind:"definition", mastery:"mastered" }, { id:"limit_func", label:"Limit · func", kind:"definition", mastery:"mastered" }, { id:"epsilon_delta", label:"ε–δ", kind:"definition", mastery:"learning" }, { id:"limit_sum", label:"Limit sum", kind:"lemma", mastery:"mastered" }, { id:"limit_product", label:"Limit product", kind:"lemma", mastery:"learning" }, { id:"limit_compose", label:"Limit compose", kind:"lemma", mastery:"learning" }, { id:"continuity", label:"Continuity", kind:"definition", mastery:"learning" }, { id:"secant", label:"Secant line", kind:"definition", mastery:"frontier" }, { id:"diff_quot", label:"Diff. quotient", kind:"definition", mastery:"frontier" }, { id:"derivative", label:"Derivative", kind:"definition", mastery:"frontier", focus:true }, { id:"diff_implies_cont", label:"Diff ⇒ cont", kind:"theorem", mastery:"mastered" }, { id:"sum_rule", label:"Sum rule", kind:"theorem", mastery:"mastered" }, { id:"product_rule", label:"Product rule", kind:"theorem", mastery:"learning" }, { id:"chain_rule", label:"Chain rule", kind:"theorem", mastery:"frontier" }, { id:"mvt", label:"MVT", kind:"theorem", mastery:"locked" }, { id:"l_hopital", label:"L'Hôpital", kind:"theorem", mastery:"locked" }, { id:"taylor", label:"Taylor", kind:"theorem", mastery:"locked" }, { id:"newtons_method",label:"Newton's method", kind:"procedure", mastery:"locked" }, ]; const _GRAPH_EDGES = [ ["function","derivative","USES"],["limit_func","derivative","USES"], ["diff_quot","derivative","DEFINES"],["secant","derivative","USES"], ["continuity","derivative","USES"],["interval","derivative","USES"], ["real_numbers","limit_seq","USES"],["set","function","USES"], ["function","limit_func","USES"],["function","composition","USES"], ["limit_seq","limit_func","GENERALIZES"],["limit_func","epsilon_delta","DEFINES"], ["limit_func","limit_sum","USES"],["limit_func","limit_product","USES"], ["limit_func","limit_compose","USES"],["limit_func","continuity","DEFINES"], ["slope_line","secant","USES"],["slope_line","diff_quot","USES"], ["function","secant","USES"],["absolute_val","continuity","USES"], ["derivative","diff_implies_cont","PROVES"],["derivative","sum_rule","PROVES"], ["derivative","product_rule","PROVES"],["derivative","chain_rule","PROVES"], ["limit_sum","sum_rule","USES"],["limit_product","product_rule","USES"], ["limit_compose","chain_rule","USES"],["continuity","diff_implies_cont","USES"], ["diff_implies_cont","mvt","USES"],["derivative","mvt","USES"], ["derivative","l_hopital","USES"],["derivative","taylor","USES"], ["derivative","newtons_method","USES"], ]; const _nodeFill = (m) => m==="mastered"?"var(--ink)":m==="frontier"?"var(--accent)":"var(--paper)"; const _nodeStroke = (m) => m==="locked"?"var(--rule-2)":m==="frontier"?"var(--accent)":"var(--ink)"; const _drawShape = (n, cx, cy) => { const fill = _nodeFill(n.mastery), stroke = _nodeStroke(n.mastery); if (n.kind === "theorem" || n.kind === "lemma") { return ; } if (n.kind === "axiom") { return ; } if (n.kind === "procedure") { return ; } return ; }; // ── Force layout ──────────────────────────────────────────── const ForceLayout = () => { // Hand-laid coordinates that approximate force-directed equilibrium. // Derivative is a hub; theorems pull outward; mastered foundations cluster. const positions = { real_numbers:[0.18,0.72], set:[0.10,0.58], function:[0.22,0.50], interval:[0.32,0.70], sequence:[0.06,0.80], slope_line:[0.28,0.88], absolute_val:[0.22,0.30], composition:[0.78,0.20], limit_seq:[0.26,0.62], limit_func:[0.40,0.42], epsilon_delta:[0.50,0.20], limit_sum:[0.62,0.30], limit_product:[0.74,0.34], limit_compose:[0.82,0.42], continuity:[0.34,0.30], secant:[0.42,0.66], diff_quot:[0.50,0.62], derivative:[0.54,0.50], diff_implies_cont:[0.42,0.16], sum_rule:[0.62,0.62], product_rule:[0.72,0.62], chain_rule:[0.78,0.54], mvt:[0.66,0.86], l_hopital:[0.78,0.80], taylor:[0.90,0.62], newtons_method:[0.92,0.30], }; const W = 1180, H = 720, PAD = 60; const xToPx = (x) => PAD + x*(W-2*PAD), yToPx = (y) => PAD + y*(H-2*PAD); const byId = Object.fromEntries(_GRAPH_NODES.map(n => [n.id, n])); const edgeColor = (t) => t==="DEFINES"?"var(--accent)":t==="PROVES"?"var(--ink)":"var(--ink-3)"; return ( {/* faint org cells around clusters */} FOUNDATIONS LIMITS · CONTINUITY THEOREMS {_GRAPH_EDGES.map(([a,b,t], i) => { const pa = positions[a], pb = positions[b]; if (!pa || !pb) return null; return ; })} {_GRAPH_NODES.map(n => { const p = positions[n.id]; if (!p) return null; const cx = xToPx(p[0]), cy = yToPx(p[1]); return ( {_drawShape(n, cx, cy)} {n.focus && } {n.label} ); })} ); }; // ── Embedding layout ──────────────────────────────────────── const EmbeddingLayout = () => { // qwen3 1024-dim → UMAP 2D. Hand-placed to put semantic neighbors close. // Note: edges still drawn but visually quieter — the projection isn't about prereqs. const positions = { // limit cluster limit_func:[0.30,0.32], limit_seq:[0.24,0.40], epsilon_delta:[0.38,0.26], limit_sum:[0.20,0.30], limit_product:[0.16,0.36], limit_compose:[0.22,0.20], continuity:[0.32,0.46], // derivative + neighbors (dense semantic cluster) derivative:[0.58,0.50], diff_quot:[0.54,0.56], secant:[0.50,0.60], slope_line:[0.46,0.66], chain_rule:[0.66,0.46], product_rule:[0.66,0.56], sum_rule:[0.62,0.60], diff_implies_cont:[0.46,0.42], // function/structure cluster function:[0.74,0.78], composition:[0.80,0.74], set:[0.86,0.82], real_numbers:[0.78,0.86], interval:[0.84,0.88], sequence:[0.70,0.84], absolute_val:[0.92,0.74], // theorem cluster (downstream) mvt:[0.78,0.30], l_hopital:[0.84,0.36], taylor:[0.88,0.26], newtons_method:[0.92,0.46], }; const W = 1180, H = 720, PAD = 60; const xToPx = (x) => PAD + x*(W-2*PAD), yToPx = (y) => PAD + y*(H-2*PAD); // semantic clusters const clusters = [ { cx:0.26, cy:0.32, rx:140, ry:120, label:"LIMITS", color:"var(--rule-3)" }, { cx:0.56, cy:0.54, rx:160, ry:130, label:"DERIVATIVE NEIGHBORHOOD", color:"var(--accent)", emph:true }, { cx:0.80, cy:0.80, rx:160, ry:100, label:"FUNCTION · STRUCTURE", color:"var(--rule-3)" }, { cx:0.84, cy:0.34, rx:140, ry:100, label:"DOWNSTREAM THEOREMS", color:"var(--rule-3)" }, ]; return ( {/* cluster envelopes */} {clusters.map((c, i) => ( {c.label} ))} {/* faint prereq edges (de-emphasized) */} {_GRAPH_EDGES.map(([a,b,t], i) => { const pa = positions[a], pb = positions[b]; if (!pa || !pb) return null; return ; })} {/* iso-distance rings around derivative */} {[60, 130, 220].map((r, i) => ( ))} {_GRAPH_NODES.map(n => { const p = positions[n.id]; if (!p) return null; const cx = xToPx(p[0]), cy = yToPx(p[1]); // distance to derivative for label decoration const dp = positions.derivative; const d = Math.hypot(p[0]-dp[0], p[1]-dp[1]); return ( {_drawShape(n, cx, cy)} {n.focus && } {n.label} {n.id !== "derivative" && d < 0.20 && ( d={d.toFixed(2)} )} ); })} {/* axes annotations */} UMAP 2D · qwen3 1024-dim · cosine semantic projection · 26 / 14,082 nodes ); }; window.ForceLayout = ForceLayout; window.EmbeddingLayout = EmbeddingLayout;