// FPGABench Model Dataset // Metrics: // - feasible: Feasible@1 (adapted pass@1) as a decimal fraction (0.0 to 1.0) // - moq: MOQ@1 (mean design quality index) normalized around 1.0 (higher is better) const modelsData = [ { id: "gpt-5", name: "GPT-5", developer: "OpenAI", type: "Proprietary", feasible: 25 / 52, moq: 1.15, lutCount: 2180, frequency: 212.5, power: 0.24, link: "https://openai.com" }, { id: "gemini-3-pro", name: "Gemini 3 Pro", developer: "Google", type: "Proprietary", feasible: 22 / 52, moq: 1.05, lutCount: 2250, frequency: 205.0, power: 0.26, link: "https://deepmind.google" }, { id: "claude-sonnet-4-5", name: "Claude Sonnet 4.5", developer: "Anthropic", type: "Proprietary", feasible: 19 / 52, moq: 1.11, lutCount: 2210, frequency: 208.4, power: 0.25, link: "https://anthropic.com" }, { id: "kimi-k2-5", name: "Kimi K2.5", developer: "Moonshot AI", type: "Proprietary", feasible: 17 / 52, moq: 1.23, lutCount: 2020, frequency: 228.2, power: 0.21, link: "https://www.moonshot.cn" }, { id: "deepseek-v3", name: "DeepSeek V3", developer: "DeepSeek", type: "Open Source", feasible: 9 / 52, moq: 1.22, lutCount: 2050, frequency: 224.8, power: 0.22, link: "https://github.com/deepseek-ai" }, { id: "qwen3-coder", name: "Qwen3 Coder", developer: "Alibaba Cloud", type: "Open Source", feasible: 8 / 52, moq: 1.07, lutCount: 2280, frequency: 201.5, power: 0.27, link: "https://github.com/QwenLM" }, { id: "meta-llama-3-1", name: "Meta Llama 3.1", developer: "Meta", type: "Open Source", feasible: 0 / 52, moq: null, lutCount: null, frequency: null, power: null, link: "https://llama.meta.com" }, { id: "qwen-2-5-coder", name: "Qwen 2.5 Coder", developer: "Alibaba Cloud", type: "Open Source", feasible: 0 / 52, moq: null, lutCount: null, frequency: null, power: null, link: "https://github.com/QwenLM" } ]; // App State Management let currentSortColumn = "rank"; let currentSortDirection = "asc"; // "asc" or "desc" let searchFilter = ""; let licenseFilter = "all"; let frontierChart = null; // Pareto Frontier Calculation // A point is on the frontier if it is not dominated by any other point. // Dominates = both feasibility and MOQ are larger/equal, and at least one is strictly larger. function calculateParetoFrontier(data) { const frontier = []; const validData = data.filter(d => d.moq !== null && d.moq !== undefined); for (const item of validData) { let dominated = false; for (const other of validData) { if (other.id === item.id) continue; if (other.feasible >= item.feasible && other.moq >= item.moq) { if (other.feasible > item.feasible || other.moq > item.moq) { dominated = true; break; } } } if (!dominated) { frontier.push(item); } } // Sort by feasibility ascending to draw a continuous curve from left to right return frontier.sort((a, b) => a.feasible - b.feasible); } // Compute overall ranks based on Feasible@1 (primary) and MOQ@1 (secondary tie-breaker) function computeModelRanks() { const sorted = [...modelsData].sort((a, b) => { if (b.feasible !== a.feasible) { return b.feasible - a.feasible; } const moqA = a.moq !== null ? a.moq : -1; const moqB = b.moq !== null ? b.moq : -1; return moqB - moqA; }); sorted.forEach((model, index) => { model.computedRank = index + 1; }); } // Set initial global stats on page load function populateGlobalStats() { document.getElementById("total-models-val").textContent = modelsData.length; const maxFeasible = Math.max(...modelsData.map(m => m.feasible)); document.getElementById("top-feasible-val").textContent = `${(maxFeasible * 100).toFixed(1)}%`; const validMoqs = modelsData.map(m => m.moq).filter(moq => moq !== null && moq !== undefined); const maxMOQ = validMoqs.length > 0 ? Math.max(...validMoqs) : 0; document.getElementById("top-moq-val").textContent = maxMOQ > 0 ? maxMOQ.toFixed(2) : "—"; } // Render Leaderboard Table function renderLeaderboard() { const tbody = document.getElementById("leaderboard-body"); tbody.innerHTML = ""; // Apply filters let filteredData = modelsData.filter(model => { const matchesSearch = model.name.toLowerCase().includes(searchFilter.toLowerCase()) || model.developer.toLowerCase().includes(searchFilter.toLowerCase()); const matchesLicense = licenseFilter === "all" || model.type === licenseFilter; return matchesSearch && matchesLicense; }); // Apply sorting filteredData.sort((a, b) => { let valA, valB; if (currentSortColumn === "rank") { valA = a.computedRank; valB = b.computedRank; } else { valA = a[currentSortColumn]; valB = b[currentSortColumn]; } if (typeof valA === "string") { return currentSortDirection === "asc" ? valA.localeCompare(valB) : valB.localeCompare(valA); } else { return currentSortDirection === "asc" ? valA - valB : valB - valA; } }); if (filteredData.length === 0) { tbody.innerHTML = ` No models matched your search or filter criteria. `; return; } filteredData.forEach(model => { const rankClass = model.computedRank === 1 ? "rank-1" : model.computedRank === 2 ? "rank-2" : model.computedRank === 3 ? "rank-3" : "rank-other"; const licenseBadgeClass = model.type === "Open Source" ? "badge-open" : "badge-proprietary"; // Create base data row const row = document.createElement("tr"); row.className = `model-row ${rankClass}`; row.id = `row-${model.id}`; row.setAttribute("data-model-id", model.id); // Feasible percent & MOQ bar fills const feasiblePct = (model.feasible * 100).toFixed(1); const feasibleBarWidth = model.feasible * 100; const isMoqValid = model.moq !== null && model.moq !== undefined; const moqText = isMoqValid ? model.moq.toFixed(2) : "—"; const moqBarWidth = isMoqValid ? Math.min(model.moq * 65, 100) : 0; row.innerHTML = ` ${model.computedRank} ${model.name} ${model.developer} ${model.type}
${feasiblePct}%
${moqText}
`; // Create details/expandable row const detailsRow = document.createElement("tr"); detailsRow.className = "details-row"; detailsRow.id = `details-${model.id}`; const lutText = (model.lutCount !== null && model.lutCount !== undefined) ? model.lutCount.toLocaleString() : "—"; const freqText = (model.frequency !== null && model.frequency !== undefined) ? `${model.frequency.toFixed(1)} MHz` : "—"; const powerText = (model.power !== null && model.power !== undefined) ? `${model.power.toFixed(2)} W` : "—"; detailsRow.innerHTML = `
Estimated LUT Usage ${lutText} Lower is better (Area optimization)
Max Freq (Fmax) ${freqText} Higher is better (Performance optimization)
Dynamic Power ${powerText} Lower is better (Power optimization)

Hardware synthesizability verified post-routing using FPGABench automation.

Visit Model Website →
`; tbody.appendChild(row); tbody.appendChild(detailsRow); // Setup expandable row click listener const toggleBtn = row.querySelector(".btn-toggle-details"); row.addEventListener("click", (e) => { // Don't expand if user clicked a link if (e.target.tagName === "A" || e.target.closest("a")) return; toggleDetails(model.id, toggleBtn); }); // Hover mapping: Hovering table highlights scatter dot row.addEventListener("mouseenter", () => { highlightChartPoint(model.id, true); }); row.addEventListener("mouseleave", () => { highlightChartPoint(model.id, false); }); }); } // Toggle detail row expansion function toggleDetails(modelId, button) { const content = document.getElementById(`details-content-${modelId}`); const isExpanded = button.classList.contains("expanded"); // Collapse all other detail rows first for accordion feel (clean UI) document.querySelectorAll(".btn-toggle-details.expanded").forEach(btn => { if (btn !== button) { const mid = btn.closest(".model-row").getAttribute("data-model-id"); const otherContent = document.getElementById(`details-content-${mid}`); otherContent.style.height = "0px"; btn.classList.remove("expanded"); btn.setAttribute("aria-expanded", "false"); } }); if (isExpanded) { content.style.height = "0px"; button.classList.remove("expanded"); button.setAttribute("aria-expanded", "false"); } else { // Set to scrollHeight to animate correctly content.style.height = content.scrollHeight + "px"; button.classList.add("expanded"); button.setAttribute("aria-expanded", "true"); } } // Handle dynamic sorting clicking on columns function setupSorting() { const headers = document.querySelectorAll("th.sortable"); headers.forEach(header => { header.addEventListener("click", () => { const sortColumn = header.getAttribute("data-sort"); if (currentSortColumn === sortColumn) { // Toggle direction currentSortDirection = currentSortDirection === "asc" ? "desc" : "asc"; } else { currentSortColumn = sortColumn; // Default directions based on column type currentSortDirection = (sortColumn === "feasible" || sortColumn === "moq") ? "desc" : "asc"; } // Update UI classes on header headers.forEach(h => { h.classList.remove("sorted-asc", "sorted-desc"); const indicator = h.querySelector(".sort-indicator"); indicator.textContent = "↕"; }); header.classList.add(currentSortDirection === "asc" ? "sorted-asc" : "sorted-desc"); header.querySelector(".sort-indicator").textContent = currentSortDirection === "asc" ? "↑" : "↓"; renderLeaderboard(); }); }); } // Setup search input and filter dropdown listeners function setupFilters() { const searchInput = document.getElementById("model-search"); const licenseFilterSelect = document.getElementById("type-filter"); searchInput.addEventListener("input", (e) => { searchFilter = e.target.value; renderLeaderboard(); updateChartOpacity(); // Dim models in chart that don't match filters }); licenseFilterSelect.addEventListener("change", (e) => { licenseFilter = e.target.value; renderLeaderboard(); updateChartOpacity(); // Dim models in chart that don't match filters }); } // --- Chart.js Setup & Integration --- function initFrontierChart() { const ctx = document.getElementById("frontierChart").getContext("2d"); // Calculate Pareto Frontier curve data const frontierPoints = calculateParetoFrontier(modelsData); // Format scatter data (filter out models with no MOQ) const validModels = modelsData.filter(model => model.moq !== null && model.moq !== undefined); const scatterData = validModels.map(model => ({ x: model.feasible * 100, // X-axis: Feasible@1 in % y: model.moq, // Y-axis: MOQ@1 index id: model.id, name: model.name, dev: model.developer, type: model.type })); // Format line curve data (draw a smooth spline through the frontier points) // To make the line look smooth and go slightly past edges, we sort it. const lineData = frontierPoints.map(model => ({ x: model.feasible * 100, y: model.moq })); frontierChart = new Chart(ctx, { type: "scatter", data: { datasets: [ { label: "Pareto Frontier", data: lineData, type: "line", borderColor: "#7c3aed", // Purple frontier line borderWidth: 3, tension: 0.35, // Smooth curves fill: false, pointRadius: 0, // Hide points on the line dataset, rely on the scatter dataset order: 1, hoverRadius: 0 }, { label: "Models", data: scatterData, backgroundColor: (context) => { const index = context.dataIndex; const model = context.dataset.data[index]; if (!model) return "rgba(2, 132, 199, 0.75)"; // Check if point is on the Pareto frontier to style differently const isOnFrontier = frontierPoints.some(f => f.id === model.id); return isOnFrontier ? "#7c3aed" : "#0284c7"; // Purple for frontier, Sky Blue for others }, borderColor: "#ffffff", borderWidth: 2, pointRadius: 8, pointHoverRadius: 12, pointHoverBackgroundColor: "#fff", pointHoverBorderColor: "#7c3aed", pointHoverBorderWidth: 3, order: 0 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false // Using custom styled legend in HTML instead }, tooltip: { backgroundColor: "#ffffff", titleColor: "#0f172a", bodyColor: "#334155", titleFont: { family: "Space Grotesk", size: 14, weight: "bold" }, bodyFont: { family: "Plus Jakarta Sans", size: 13 }, borderColor: "rgba(15, 23, 42, 0.08)", borderWidth: 1, padding: 12, cornerRadius: 8, displayColors: false, callbacks: { title: (context) => { const model = context[0].raw; return model.name || "Pareto Frontier Line"; }, label: (context) => { const model = context.raw; if (model.id) { return [ `Developer: ${model.dev}`, `Feasible@1: ${model.x.toFixed(1)}%`, `MOQ@1: ${model.y.toFixed(2)}` ]; } return `Frontier MOQ: ${model.y.toFixed(2)} at Feasible: ${model.x.toFixed(1)}%`; } } } }, scales: { x: { title: { display: true, text: "Feasible@1 Success Rate (%)", color: "#334155", font: { family: "Space Grotesk", size: 13, weight: "bold" } }, grid: { color: "rgba(15, 23, 42, 0.05)" }, ticks: { color: "#475569", font: { family: "JetBrains Mono" }, callback: (value) => `${value}%` }, min: 0, max: 60 }, y: { title: { display: true, text: "MOQ@1 Design Quality Index (Normalized)", color: "#334155", font: { family: "Space Grotesk", size: 13, weight: "bold" } }, grid: { color: "rgba(15, 23, 42, 0.05)" }, ticks: { color: "#475569", font: { family: "JetBrains Mono" } }, min: 1.0, max: 1.26 } }, onHover: (event, activeElements) => { // Change cursor to pointer if hovering over points event.chart.canvas.style.cursor = activeElements.length ? "pointer" : "default"; // Link Hover: Highlight table row when hovering chart point if (activeElements.length > 0) { const index = activeElements[0].index; const datasetIndex = activeElements[0].datasetIndex; if (datasetIndex === 1) { // Models scatter dataset const model = event.chart.data.datasets[1].data[index]; highlightTableRow(model.id); } } else { clearTableHighlights(); } } } }); } // Sync highlight: Table row hover -> Chart point highlight function highlightChartPoint(modelId, highlight) { if (!frontierChart) return; const dataset = frontierChart.data.datasets[1]; const modelIndex = dataset.data.findIndex(p => p.id === modelId); if (modelIndex !== -1) { const meta = frontierChart.getDatasetMeta(1); const point = meta.data[modelIndex]; if (highlight) { // Force active hover styling in Chart.js frontierChart.tooltip.setActiveElements([{ datasetIndex: 1, index: modelIndex }], { x: point.x, y: point.y }); // Set visual state point.options.radius = 12; point.options.backgroundColor = "#fff"; point.options.borderColor = "#8b5cf6"; point.options.borderWidth = 3; } else { // Reset active elements frontierChart.tooltip.setActiveElements([], { x: 0, y: 0 }); // Reset visual state point.options.radius = undefined; // defaults back point.options.backgroundColor = undefined; point.options.borderColor = undefined; point.options.borderWidth = undefined; } frontierChart.update("none"); // Update without animation loops for performance } } // Sync highlight: Chart point hover -> Table row highlight let lastHighlightedRow = null; function highlightTableRow(modelId) { clearTableHighlights(); const row = document.getElementById(`row-${modelId}`); if (row) { row.classList.add("row-active"); lastHighlightedRow = row; // Smoothly scroll the highlighted row into view if it's outside the scroll container view // (Only if it's not already in view, to prevent jarring screen jumps) const tableWrapper = row.closest(".table-wrapper"); const rowTop = row.offsetTop; const rowBottom = rowTop + row.offsetHeight; const scrollContainerTop = tableWrapper.scrollTop; const scrollContainerBottom = scrollContainerTop + tableWrapper.offsetHeight; if (rowTop < scrollContainerTop) { tableWrapper.scrollTo({ top: rowTop - 20, behavior: "smooth" }); } else if (rowBottom > scrollContainerBottom) { tableWrapper.scrollTo({ top: rowBottom - tableWrapper.offsetHeight + 20, behavior: "smooth" }); } } } function clearTableHighlights() { if (lastHighlightedRow) { lastHighlightedRow.classList.remove("row-active"); lastHighlightedRow = null; } } // Update chart point opacities based on active filters (dim non-matching models) function updateChartOpacity() { if (!frontierChart) return; const filteredIds = modelsData .filter(model => { const matchesSearch = model.name.toLowerCase().includes(searchFilter.toLowerCase()) || model.developer.toLowerCase().includes(searchFilter.toLowerCase()); const matchesLicense = licenseFilter === "all" || model.type === licenseFilter; return matchesSearch && matchesLicense; }) .map(model => model.id); // Dynamically update point background opacity const frontierPoints = calculateParetoFrontier(modelsData); frontierChart.data.datasets[1].backgroundColor = (context) => { const index = context.dataIndex; const model = context.dataset.data[index]; if (!model) return "rgba(2, 132, 199, 0.75)"; const isFiltered = filteredIds.includes(model.id); const isOnFrontier = frontierPoints.some(f => f.id === model.id); const baseColor = isOnFrontier ? "124, 58, 237" : "2, 132, 199"; // purple vs blue RGB const opacity = isFiltered ? "1.0" : "0.15"; return `rgba(${baseColor}, ${opacity})`; }; frontierChart.data.datasets[1].borderColor = (context) => { const index = context.dataIndex; const model = context.dataset.data[index]; if (!model) return "rgba(15, 23, 42, 0.2)"; const isFiltered = filteredIds.includes(model.id); const opacity = isFiltered ? "1.0" : "0.15"; return `rgba(255, 255, 255, ${opacity})`; }; frontierChart.update(); } // --- Page Initialization --- document.addEventListener("DOMContentLoaded", () => { computeModelRanks(); populateGlobalStats(); renderLeaderboard(); setupSorting(); setupFilters(); // Initialize Chart after a brief timeout to let grid layout render properly setTimeout(() => { initFrontierChart(); }, 100); });