Spaces:
Running
Running
Complete medium_posts results and restore dataset timing averages
Browse filesIntegrate the verified C++, Java, and Python medium_posts measurement into the existing leaderboard. Use equal-dataset timing averages when selected results contain aggregate-only timing evidence, while retaining equal-column averages for fully column-backed results. Refresh scores, ranks, compact data, and provenance.
- README.md +11 -3
- app.js +15 -8
- apply_dataset_scope.py +12 -0
- build_ui_payload.py +3 -1
- data.json +2 -2
- export_results.py +93 -47
- index.html +3 -3
- manifest.json +69 -9
- ui-data.json +0 -0
README.md
CHANGED
|
@@ -24,8 +24,13 @@ python3 deploy/huggingface-compressionbenchmark/export_results.py
|
|
| 24 |
python3 deploy/huggingface-compressionbenchmark/apply_dataset_scope.py
|
| 25 |
# Reapply verified measurement updates before packing the browser payload.
|
| 26 |
python3 scripts/integrate_dbp_leaderboard.py --measurements /path/to/frozen-measurements.json --expected-sha256 VERIFIED_SHA256 --receipt /path/to/integration-receipt.json
|
| 27 |
-
# Verify
|
| 28 |
-
python3 scripts/update_site_column_means.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
python3 deploy/huggingface-compressionbenchmark/build_ui_payload.py
|
| 30 |
```
|
| 31 |
|
|
@@ -47,6 +52,9 @@ The summary dataset count and Dataset coverage denominator use the same measured
|
|
| 47 |
|
| 48 |
The Overall score is `a × average rate + b × normalized average compression time + c × normalized average decompression time`. Time normalization is linear min–max across all eligible rows in the selected runtime, scope and row mode; an equal-time range normalizes to zero. Search, family and coverage filters only hide rows and never change the reference. Average Rank averages per-dataset composite-score ranks with dataset-local time normalization and fractional ties. Missing results are omitted. Coverage and candidate counts can differ across datasets; method details expose dataset scores, ranks and candidate counts. CSV downloads include weights, normalization bounds and rank coverage. The default weights are `a=0.4, b=0.3, c=0.3`.
|
| 49 |
|
| 50 |
-
Compression and decompression costs are calculated independently for each usable numeric column as ns/point, then reported as the arithmetic mean across those columns; each column contributes equally. Overall timing pools all measured columns across the selected datasets. If any selected dataset/configuration
|
| 51 |
|
| 52 |
Source project: https://github.com/xjz17/web_compression
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
python3 deploy/huggingface-compressionbenchmark/apply_dataset_scope.py
|
| 25 |
# Reapply verified measurement updates before packing the browser payload.
|
| 26 |
python3 scripts/integrate_dbp_leaderboard.py --measurements /path/to/frozen-measurements.json --expected-sha256 VERIFIED_SHA256 --receipt /path/to/integration-receipt.json
|
| 27 |
+
# Verify source identities, rebuild timing averages, and reapply the targeted retest.
|
| 28 |
+
python3 scripts/update_site_column_means.py \
|
| 29 |
+
--receipt /path/to/timing-fallback-receipt.json \
|
| 30 |
+
--dbp-medium-payload analysis_outputs/column_mean_20261009/dbp_medium_posts_retest/integration_payload.json \
|
| 31 |
+
--dbp-medium-payload-sha256 e45170a955d1cd0df50dba25f9e41f24f00fc8b559e702d59188b6cfa60c99dc \
|
| 32 |
+
--dbp-medium-receipt analysis_outputs/column_mean_20261009/dbp_medium_posts_retest/measurement_receipt.json \
|
| 33 |
+
--dbp-medium-receipt-sha256 10359f6f1153655710f7ce9b59d04e5460babe5606487b7794a47ba874ef4324
|
| 34 |
python3 deploy/huggingface-compressionbenchmark/build_ui_payload.py
|
| 35 |
```
|
| 36 |
|
|
|
|
| 52 |
|
| 53 |
The Overall score is `a × average rate + b × normalized average compression time + c × normalized average decompression time`. Time normalization is linear min–max across all eligible rows in the selected runtime, scope and row mode; an equal-time range normalizes to zero. Search, family and coverage filters only hide rows and never change the reference. Average Rank averages per-dataset composite-score ranks with dataset-local time normalization and fractional ties. Missing results are omitted. Coverage and candidate counts can differ across datasets; method details expose dataset scores, ranks and candidate counts. CSV downloads include weights, normalization bounds and rank coverage. The default weights are `a=0.4, b=0.3, c=0.3`.
|
| 54 |
|
| 55 |
+
Compression and decompression costs are calculated independently for each usable numeric column as ns/point, then reported as the arithmetic mean across those columns; each column contributes equally. Overall timing pools all measured columns across the selected datasets when every selected dataset has column-level evidence. If any selected dataset/configuration is backed only by aggregate timing, the method uses an arithmetic mean of its selected per-dataset ns/point values, giving every dataset equal weight. Aggregate-only dataset timing uses recorded elapsed time divided by recorded points; these records keep a zero measured-column count. Truly missing measurements remain unavailable. Method details and CSV expose the timing basis. Native-float measurements use valid native values; historical imported rows retain their source 8-byte-equivalent point definition. Timing comparisons should therefore stay within the same runtime and measurement contract.
|
| 56 |
|
| 57 |
Source project: https://github.com/xjz17/web_compression
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
The timing updater verifies the input hashes, replaces existing dataset/runtime/scope rows by identity, and adds only missing rows. The measurement harness and its frozen-source instructions are in `scripts/dbp_medium_posts_retest/`; raw data and compiled binaries are excluded from Git.
|
app.js
CHANGED
|
@@ -3,10 +3,17 @@ const $ = (id) => document.getElementById(id);
|
|
| 3 |
const escape = (value) => String(value ?? '').replace(/[&<>"']/g, (c) => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
| 4 |
const number = (v) => v != null && Number.isFinite(Number(v)) ? Number(v) : null;
|
| 5 |
const mean = (values) => { const a = values.map(number).filter((n) => n !== null); return a.length ? a.reduce((s,n) => s+n,0)/a.length : null; };
|
| 6 |
-
function
|
| 7 |
-
if(!input.length||input.some(r=>number(r
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
return input.reduce((sum,r)=>sum+r[key]*r.timing_column_count,0)/input.reduce((sum,r)=>sum+r.timing_column_count,0);
|
| 9 |
}
|
|
|
|
| 10 |
const fmt = (v, digits=3) => number(v) === null ? 'Not reported' : Number(v).toLocaleString('en-US',{maximumFractionDigits:digits,minimumFractionDigits:digits});
|
| 11 |
const countFmt = (v) => Number(v).toLocaleString('en-US');
|
| 12 |
const runtimeName = (v) => ({cpp:'C++',java:'Java',python:'Python'}[v] || v);
|
|
@@ -55,7 +62,7 @@ function aggregate(input) {
|
|
| 55 |
for(const [method,source] of groups) {
|
| 56 |
const hasBytes=source.every(r=>r.original_bytes!==null && r.original_bytes>0 && r.compressed_bytes!==null && r.compressed_bytes>0);
|
| 57 |
const original=hasBytes?source.reduce((s,r)=>s+r.original_bytes,0):null, compressed=hasBytes?source.reduce((s,r)=>s+r.compressed_bytes,0):null;
|
| 58 |
-
rows.push({method,family:source[0].family,runtime:source[0].runtime,compression_rate:mean(source.map(r=>r.compression_rate)),compression_time:
|
| 59 |
}
|
| 60 |
const s=state();
|
| 61 |
return addRankingMetrics(rows,parseWeights($('weights').value)).filter(r=>(s.family==='all'||r.family===s.family)&&(!s.search||(s.mode==='family'?r.family:`${r.method} ${r.family}`).toLowerCase().includes(s.search))&&(!s.complete||r.coverage===totalDatasets)).sort((a,b)=>{
|
|
@@ -78,7 +85,7 @@ function renderTable() {
|
|
| 78 |
function refresh() {
|
| 79 |
if(!snapshot)return;
|
| 80 |
$('precision').disabled=$('dtype').value!=='float';
|
| 81 |
-
const selectedDataset=state().dataset,selectedHasMeasurements=selectedDataset==='all'||records.some(r=>r.dataset===selectedDataset),columnCoverageNote='Compress and Decompress times
|
| 82 |
if(!selectedHasMeasurements) {
|
| 83 |
$('results-note').textContent=`No published measurements are available for this catalog dataset. It is excluded from rankings rather than treated as zero. ${columnCoverageNote}`;
|
| 84 |
} else if(scopeKey()==='float'&&!records.some(r=>r.scope==='float')) {
|
|
@@ -115,7 +122,7 @@ function showMethod(method,focus=false) {
|
|
| 115 |
if(!row){selectedMethod=null;detail.hidden=true;return;}selectedMethod=method;
|
| 116 |
const meta=methods.get(method)??methods.get(row.source[0].configuration), pipeline=meta?.operator_pipeline;
|
| 117 |
const source=row.source.slice().sort((a,b)=>a.dataset.localeCompare(b.dataset));
|
| 118 |
-
detail.innerHTML=`<div class="detail-head"><div><h2 id="detail-title">${escape(method)}</h2><p class="muted">${escape(row.family)} · ${escape(runtimeName(row.runtime))} · ${row.coverage} measured datasets</p></div><button id="close-detail" class="quiet-button">Close details</button></div><div class="detail-grid"><div><strong>${fmt(row.compression_rate,4)}</strong><span>average compression rate</span></div><div><strong>${fmt(row.compression_time,2)}</strong><span>Compress ns/point</span></div><div><strong>${fmt(row.decompression_time,2)}</strong><span>Decompress ns/point</span></div><div><strong>${row.coverage} / ${row.totalDatasets}</strong><span>dataset coverage</span></div></div>${pipeline?`<p class="source-code">Interpretive operator mapping: ${escape(typeof pipeline==='string'?pipeline:JSON.stringify(pipeline))}</p>`:''}<p class="muted">Dataset metrics below come from the published result files. Measurement boundaries, source hashes, and available verification evidence are recorded in the manifest.</p><div class="detail-table"><table><thead><tr><th>Dataset</th><th>Configuration</th><th>Rate ↓</th><th>Compress ns/point ↓</th><th>Decompress ns/point ↓</th><th>Original bytes</th><th>Compressed bytes</th><th>Dataset score ↓</th><th>Dataset Rank ↓</th><th>Rank candidates</th></tr></thead><tbody>${source.map(r=>`<tr><td>${escape(r.dataset)}</td><td>${escape(r.configuration)}</td><td class="numeric">${fmt(r.compression_rate,4)}</td><td class="numeric">${fmt(r.compression_time,2)}</td><td class="numeric">${fmt(r.decompression_time,2)}</td><td class="numeric">${fmt(r.original_bytes,0)}</td><td class="numeric">${fmt(r.compressed_bytes,0)}</td><td class="numeric">${fmt(r.dataset_score,4)}</td><td class="numeric">${fmt(r.dataset_rank,2)}</td><td class="numeric">${fmt(r.dataset_candidate_count,0)}</td></tr>`).join('')}</tbody></table></div>`;
|
| 119 |
detail.hidden=false;$('close-detail').addEventListener('click',()=>{detail.hidden=true;selectedMethod=null;});
|
| 120 |
if(focus){detail.scrollIntoView({block:'nearest',behavior:'auto'});detail.focus({preventScroll:true});}
|
| 121 |
}
|
|
@@ -139,7 +146,7 @@ function csv() {
|
|
| 139 |
const quote=v=>{let text=String(v??'');if(typeof v==='string'&&/^[=+@-]/.test(text))text="'"+text;return `"${text.replace(/"/g,'""')}"`;};
|
| 140 |
const weights=parseWeights($('weights').value);
|
| 141 |
const columns=['position','method','runtime','scope','row_mode','selected_dataset','sort_metric','sort_direction','average_compression_rate','overall_compression_rate','compress_ns_per_point','decompress_ns_per_point','weight_a','weight_b','weight_c','normalized_compress','normalized_decompress','composite_score','average_rank','rank_dataset_coverage','normalization_reference_rows','compress_min','compress_max','decompress_min','decompress_max','normalization','rank_definition','dataset_coverage','datasets_in_scope','selected_configuration_by_dataset','timing_column_count','timing_aggregation'];
|
| 142 |
-
const body=currentRows.map((r,i)=>[i+1,r.method,r.runtime,scopeKey(),state().mode,state().dataset,sort.key,sort.direction===1?'ascending':'descending',r.compression_rate,r.overall_rate,r.compression_time,r.decompression_time,...weights.map(w=>w.toFixed(1)),r.normalized_compression_time,r.normalized_decompression_time,r.composite_score,r.average_rank,r.rank_coverage,r.normalization_reference_rows,r.encode_min,r.encode_max,r.decode_min,r.decode_max,'min-max over all measured rows in selected runtime/scope/row-mode before search and visibility filters','mean per-dataset composite-score fractional rank; per-dataset min-max times',r.coverage,r.totalDatasets,JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.configuration]))),r.timing_column_count,
|
| 143 |
const url=URL.createObjectURL(new Blob(['\ufeff'+[columns.join(','),...body].join('\r\n')],{type:'text/csv;charset=utf-8'}));const a=document.createElement('a');a.href=url;a.download=`THULab-compression-${state().runtime}-${scopeKey()}-${state().dataset}.csv`;a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);
|
| 144 |
}
|
| 145 |
function safeHttpUrl(value) {
|
|
@@ -281,7 +288,7 @@ function renderAbout() {
|
|
| 281 |
$('provenance').innerHTML=`<table class="provenance-table"><tbody>${Object.entries(info).map(([k,v])=>`<tr><th>${escape(k)}</th><td class="source-code">${escape(v)}</td></tr>`).join('')}</tbody></table>${exclusions.length?`<h3>Excluded or unavailable results</h3><p class="source-code">${escape(typeof exclusions==='string'?exclusions:JSON.stringify(exclusions))}</p>`:''}`;
|
| 282 |
}
|
| 283 |
function init() {
|
| 284 |
-
if(snapshot.compact_records){const t=snapshot.record_tables;snapshot.dataset_results=snapshot.compact_records.map(r=>({dataset:t.datasets[r[0]],scope:t.scopes[r[1]],runtime:t.runtimes[r[2]],family:t.families[r[3]],method:t.configurations[r[4]],algorithm_variant:t.configurations[r[4]],compression_rate:r[5],compression_time_ns_per_point:r[6],decompression_time_ns_per_point:r[7],original_size_bytes:r[8],compressed_size_bytes:r[9],timing_column_count:r[10]}));delete snapshot.compact_records;}
|
| 285 |
for(const m of snapshot.methods||[]) { const method=typeof m==='string'?{name:m}:m;methods.set(method.name??method.method,method);for(const c of method.configurations||[])methods.set(c.algorithm_variant,{...method,name:c.algorithm_variant,family:method.name}); }
|
| 286 |
for(const d of snapshot.datasets||[])datasets.set(d.key??d.dataset,d);
|
| 287 |
records=(snapshot.dataset_results||snapshot.records||[]).map(normalizeRecord).filter(r=>r.method&&r.dataset&&r.compression_rate>0);
|
|
@@ -313,5 +320,5 @@ function setupTheme() {
|
|
| 313 |
setupTheme();
|
| 314 |
void loadReferenceCatalog();
|
| 315 |
void loadDatasetCatalog();
|
| 316 |
-
try { const response=await fetch('./ui-data.json?v=20261009-
|
| 317 |
catch(e){$('load-error').hidden=false;$('load-error').textContent=`The result snapshot could not be loaded. Please reload the page or download the JSON from the repository. ${e.message}`;$('snapshot').textContent='Snapshot unavailable';$('leaderboard').querySelector('tbody').innerHTML='<tr><td class="empty-cell">Results unavailable.</td></tr>';}
|
|
|
|
| 3 |
const escape = (value) => String(value ?? '').replace(/[&<>"']/g, (c) => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
| 4 |
const number = (v) => v != null && Number.isFinite(Number(v)) ? Number(v) : null;
|
| 5 |
const mean = (values) => { const a = values.map(number).filter((n) => n !== null); return a.length ? a.reduce((s,n) => s+n,0)/a.length : null; };
|
| 6 |
+
function timingMode(input) {
|
| 7 |
+
if(!input.length||input.some(r=>number(r.compression_time)===null||number(r.decompression_time)===null||!Number.isInteger(r.timing_column_count)||r.timing_column_count<0||!((r.timing_aggregation==='column_mean'&&r.timing_column_count>0)||(r.timing_aggregation==='dataset_aggregate'&&r.timing_column_count===0))))return 'unavailable';
|
| 8 |
+
return input.some(r=>r.timing_aggregation==='dataset_aggregate')?'dataset_mean':'column_mean';
|
| 9 |
+
}
|
| 10 |
+
function aggregateTime(input,key) {
|
| 11 |
+
const mode=timingMode(input);
|
| 12 |
+
if(mode==='unavailable')return null;
|
| 13 |
+
if(mode==='dataset_mean')return mean(input.map(r=>r[key]));
|
| 14 |
return input.reduce((sum,r)=>sum+r[key]*r.timing_column_count,0)/input.reduce((sum,r)=>sum+r.timing_column_count,0);
|
| 15 |
}
|
| 16 |
+
const timingLabel=mode=>({column_mean:'Equal-column arithmetic mean',dataset_mean:'Equal-dataset arithmetic mean',dataset_aggregate:'Dataset aggregate',unavailable:'Not reported'}[mode]??'Not reported');
|
| 17 |
const fmt = (v, digits=3) => number(v) === null ? 'Not reported' : Number(v).toLocaleString('en-US',{maximumFractionDigits:digits,minimumFractionDigits:digits});
|
| 18 |
const countFmt = (v) => Number(v).toLocaleString('en-US');
|
| 19 |
const runtimeName = (v) => ({cpp:'C++',java:'Java',python:'Python'}[v] || v);
|
|
|
|
| 62 |
for(const [method,source] of groups) {
|
| 63 |
const hasBytes=source.every(r=>r.original_bytes!==null && r.original_bytes>0 && r.compressed_bytes!==null && r.compressed_bytes>0);
|
| 64 |
const original=hasBytes?source.reduce((s,r)=>s+r.original_bytes,0):null, compressed=hasBytes?source.reduce((s,r)=>s+r.compressed_bytes,0):null;
|
| 65 |
+
rows.push({method,family:source[0].family,runtime:source[0].runtime,compression_rate:mean(source.map(r=>r.compression_rate)),compression_time:aggregateTime(source,'compression_time'),decompression_time:aggregateTime(source,'decompression_time'),timing_column_count:source.reduce((sum,r)=>sum+r.timing_column_count,0),timing_aggregation:timingMode(source),overall_rate:hasBytes?compressed/original:null,original_bytes:original,compressed_bytes:compressed,coverage:new Set(source.map(r=>r.dataset)).size,totalDatasets,source});
|
| 66 |
}
|
| 67 |
const s=state();
|
| 68 |
return addRankingMetrics(rows,parseWeights($('weights').value)).filter(r=>(s.family==='all'||r.family===s.family)&&(!s.search||(s.mode==='family'?r.family:`${r.method} ${r.family}`).toLowerCase().includes(s.search))&&(!s.complete||r.coverage===totalDatasets)).sort((a,b)=>{
|
|
|
|
| 85 |
function refresh() {
|
| 86 |
if(!snapshot)return;
|
| 87 |
$('precision').disabled=$('dtype').value!=='float';
|
| 88 |
+
const selectedDataset=state().dataset,selectedHasMeasurements=selectedDataset==='all'||records.some(r=>r.dataset===selectedDataset),columnCoverageNote='Compress and Decompress times use equal-column arithmetic means when every selected dataset has column timings. If a method has aggregate-only timings in the selection, its dataset ns/point values are averaged with equal weight per dataset. Timing basis is shown in method details and CSV. Column coverage may differ by method.';
|
| 89 |
if(!selectedHasMeasurements) {
|
| 90 |
$('results-note').textContent=`No published measurements are available for this catalog dataset. It is excluded from rankings rather than treated as zero. ${columnCoverageNote}`;
|
| 91 |
} else if(scopeKey()==='float'&&!records.some(r=>r.scope==='float')) {
|
|
|
|
| 122 |
if(!row){selectedMethod=null;detail.hidden=true;return;}selectedMethod=method;
|
| 123 |
const meta=methods.get(method)??methods.get(row.source[0].configuration), pipeline=meta?.operator_pipeline;
|
| 124 |
const source=row.source.slice().sort((a,b)=>a.dataset.localeCompare(b.dataset));
|
| 125 |
+
detail.innerHTML=`<div class="detail-head"><div><h2 id="detail-title">${escape(method)}</h2><p class="muted">${escape(row.family)} · ${escape(runtimeName(row.runtime))} · ${row.coverage} measured datasets</p></div><button id="close-detail" class="quiet-button">Close details</button></div><div class="detail-grid"><div><strong>${fmt(row.compression_rate,4)}</strong><span>average compression rate</span></div><div><strong>${fmt(row.compression_time,2)}</strong><span>Compress ns/point</span></div><div><strong>${fmt(row.decompression_time,2)}</strong><span>Decompress ns/point</span></div><div><strong>${row.coverage} / ${row.totalDatasets}</strong><span>dataset coverage</span></div></div>${pipeline?`<p class="source-code">Interpretive operator mapping: ${escape(typeof pipeline==='string'?pipeline:JSON.stringify(pipeline))}</p>`:''}<p class="muted">Timing average: ${escape(timingLabel(row.timing_aggregation))}. Dataset metrics below come from the published result files. Measurement boundaries, source hashes, and available verification evidence are recorded in the manifest.</p><div class="detail-table"><table><thead><tr><th>Dataset</th><th>Configuration</th><th>Rate ↓</th><th>Compress ns/point ↓</th><th>Decompress ns/point ↓</th><th>Timing basis</th><th>Original bytes</th><th>Compressed bytes</th><th>Dataset score ↓</th><th>Dataset Rank ↓</th><th>Rank candidates</th></tr></thead><tbody>${source.map(r=>`<tr><td>${escape(r.dataset)}</td><td>${escape(r.configuration)}</td><td class="numeric">${fmt(r.compression_rate,4)}</td><td class="numeric">${fmt(r.compression_time,2)}</td><td class="numeric">${fmt(r.decompression_time,2)}</td><td>${escape(timingLabel(r.timing_aggregation))}</td><td class="numeric">${fmt(r.original_bytes,0)}</td><td class="numeric">${fmt(r.compressed_bytes,0)}</td><td class="numeric">${fmt(r.dataset_score,4)}</td><td class="numeric">${fmt(r.dataset_rank,2)}</td><td class="numeric">${fmt(r.dataset_candidate_count,0)}</td></tr>`).join('')}</tbody></table></div>`;
|
| 126 |
detail.hidden=false;$('close-detail').addEventListener('click',()=>{detail.hidden=true;selectedMethod=null;});
|
| 127 |
if(focus){detail.scrollIntoView({block:'nearest',behavior:'auto'});detail.focus({preventScroll:true});}
|
| 128 |
}
|
|
|
|
| 146 |
const quote=v=>{let text=String(v??'');if(typeof v==='string'&&/^[=+@-]/.test(text))text="'"+text;return `"${text.replace(/"/g,'""')}"`;};
|
| 147 |
const weights=parseWeights($('weights').value);
|
| 148 |
const columns=['position','method','runtime','scope','row_mode','selected_dataset','sort_metric','sort_direction','average_compression_rate','overall_compression_rate','compress_ns_per_point','decompress_ns_per_point','weight_a','weight_b','weight_c','normalized_compress','normalized_decompress','composite_score','average_rank','rank_dataset_coverage','normalization_reference_rows','compress_min','compress_max','decompress_min','decompress_max','normalization','rank_definition','dataset_coverage','datasets_in_scope','selected_configuration_by_dataset','timing_column_count','timing_aggregation'];
|
| 149 |
+
const body=currentRows.map((r,i)=>[i+1,r.method,r.runtime,scopeKey(),state().mode,state().dataset,sort.key,sort.direction===1?'ascending':'descending',r.compression_rate,r.overall_rate,r.compression_time,r.decompression_time,...weights.map(w=>w.toFixed(1)),r.normalized_compression_time,r.normalized_decompression_time,r.composite_score,r.average_rank,r.rank_coverage,r.normalization_reference_rows,r.encode_min,r.encode_max,r.decode_min,r.decode_max,'min-max over all measured rows in selected runtime/scope/row-mode before search and visibility filters','mean per-dataset composite-score fractional rank; per-dataset min-max times',r.coverage,r.totalDatasets,JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.configuration]))),r.timing_column_count,r.timing_aggregation].map(quote).join(','));
|
| 150 |
const url=URL.createObjectURL(new Blob(['\ufeff'+[columns.join(','),...body].join('\r\n')],{type:'text/csv;charset=utf-8'}));const a=document.createElement('a');a.href=url;a.download=`THULab-compression-${state().runtime}-${scopeKey()}-${state().dataset}.csv`;a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);
|
| 151 |
}
|
| 152 |
function safeHttpUrl(value) {
|
|
|
|
| 288 |
$('provenance').innerHTML=`<table class="provenance-table"><tbody>${Object.entries(info).map(([k,v])=>`<tr><th>${escape(k)}</th><td class="source-code">${escape(v)}</td></tr>`).join('')}</tbody></table>${exclusions.length?`<h3>Excluded or unavailable results</h3><p class="source-code">${escape(typeof exclusions==='string'?exclusions:JSON.stringify(exclusions))}</p>`:''}`;
|
| 289 |
}
|
| 290 |
function init() {
|
| 291 |
+
if(snapshot.compact_records){const t=snapshot.record_tables;snapshot.dataset_results=snapshot.compact_records.map(r=>({dataset:t.datasets[r[0]],scope:t.scopes[r[1]],runtime:t.runtimes[r[2]],family:t.families[r[3]],method:t.configurations[r[4]],algorithm_variant:t.configurations[r[4]],compression_rate:r[5],compression_time_ns_per_point:r[6],decompression_time_ns_per_point:r[7],original_size_bytes:r[8],compressed_size_bytes:r[9],timing_column_count:r[10],timing_aggregation:t.timing_aggregations[r[11]]}));delete snapshot.compact_records;}
|
| 292 |
for(const m of snapshot.methods||[]) { const method=typeof m==='string'?{name:m}:m;methods.set(method.name??method.method,method);for(const c of method.configurations||[])methods.set(c.algorithm_variant,{...method,name:c.algorithm_variant,family:method.name}); }
|
| 293 |
for(const d of snapshot.datasets||[])datasets.set(d.key??d.dataset,d);
|
| 294 |
records=(snapshot.dataset_results||snapshot.records||[]).map(normalizeRecord).filter(r=>r.method&&r.dataset&&r.compression_rate>0);
|
|
|
|
| 320 |
setupTheme();
|
| 321 |
void loadReferenceCatalog();
|
| 322 |
void loadDatasetCatalog();
|
| 323 |
+
try { const response=await fetch('./ui-data.json?v=20261009-dataset-fallback-v1',{cache:'no-cache'});if(!response.ok)throw new Error(`Snapshot request returned ${response.status}`);snapshot=await response.json();init(); }
|
| 324 |
catch(e){$('load-error').hidden=false;$('load-error').textContent=`The result snapshot could not be loaded. Please reload the page or download the JSON from the repository. ${e.message}`;$('snapshot').textContent='Snapshot unavailable';$('leaderboard').querySelector('tbody').innerHTML='<tr><td class="empty-cell">Results unavailable.</td></tr>';}
|
apply_dataset_scope.py
CHANGED
|
@@ -93,6 +93,18 @@ def apply() -> None:
|
|
| 93 |
runtime_configuration_count=len({(r["runtime"], r["method"]) for r in rows}),
|
| 94 |
source_report_file_count=len(source["result_csv_files_used"]), paper_leaderboard_row_count=0,
|
| 95 |
excluded_datasets=sorted(excluded | set(coverage.get("excluded_datasets", []))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
data["dataset_summary"] = {**catalog["summary"], "published_measurement_dataset_count": len(measured)}
|
| 97 |
data_path.write_text(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True, allow_nan=False) + "\n")
|
| 98 |
manifest_path = ROOT / "manifest.json"
|
|
|
|
| 93 |
runtime_configuration_count=len({(r["runtime"], r["method"]) for r in rows}),
|
| 94 |
source_report_file_count=len(source["result_csv_files_used"]), paper_leaderboard_row_count=0,
|
| 95 |
excluded_datasets=sorted(excluded | set(coverage.get("excluded_datasets", []))))
|
| 96 |
+
coverage.update(
|
| 97 |
+
timing_column_observation_count=sum(r.get("timing_column_count", 0) for r in rows),
|
| 98 |
+
timing_column_mean_dataset_result_count=sum(
|
| 99 |
+
r.get("timing_aggregation") == "column_mean" for r in rows
|
| 100 |
+
),
|
| 101 |
+
timing_dataset_aggregate_result_count=sum(
|
| 102 |
+
r.get("timing_aggregation") == "dataset_aggregate" for r in rows
|
| 103 |
+
),
|
| 104 |
+
timing_unavailable_dataset_result_count=sum(
|
| 105 |
+
r.get("timing_aggregation") == "unavailable" for r in rows
|
| 106 |
+
),
|
| 107 |
+
)
|
| 108 |
data["dataset_summary"] = {**catalog["summary"], "published_measurement_dataset_count": len(measured)}
|
| 109 |
data_path.write_text(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True, allow_nan=False) + "\n")
|
| 110 |
manifest_path = ROOT / "manifest.json"
|
build_ui_payload.py
CHANGED
|
@@ -14,13 +14,15 @@ def build() -> None:
|
|
| 14 |
fields = {'datasets': 'dataset', 'scopes': 'scope', 'runtimes': 'runtime',
|
| 15 |
'families': 'family', 'configurations': 'algorithm_variant'}
|
| 16 |
tables = {key: sorted({r[field] for r in rows}) for key, field in fields.items()}
|
|
|
|
| 17 |
indices = {key: {v:i for i,v in enumerate(values)} for key,values in tables.items()}
|
| 18 |
compact = []
|
| 19 |
for r in rows:
|
| 20 |
compact.append([*(indices[key][r[field]] for key,field in fields.items()),
|
| 21 |
r['compression_rate'], r['compression_time_ns_per_point'],
|
| 22 |
r['decompression_time_ns_per_point'], r['original_size_bytes'],
|
| 23 |
-
r['compressed_size_bytes'], r.get('timing_column_count', 0)
|
|
|
|
| 24 |
payload = {key: data[key] for key in ('schema_version','benchmark','coverage','datasets','methods','scopes','source')}
|
| 25 |
if 'dataset_summary' in data:
|
| 26 |
payload['dataset_summary'] = data['dataset_summary']
|
|
|
|
| 14 |
fields = {'datasets': 'dataset', 'scopes': 'scope', 'runtimes': 'runtime',
|
| 15 |
'families': 'family', 'configurations': 'algorithm_variant'}
|
| 16 |
tables = {key: sorted({r[field] for r in rows}) for key, field in fields.items()}
|
| 17 |
+
tables['timing_aggregations'] = sorted({r['timing_aggregation'] for r in rows})
|
| 18 |
indices = {key: {v:i for i,v in enumerate(values)} for key,values in tables.items()}
|
| 19 |
compact = []
|
| 20 |
for r in rows:
|
| 21 |
compact.append([*(indices[key][r[field]] for key,field in fields.items()),
|
| 22 |
r['compression_rate'], r['compression_time_ns_per_point'],
|
| 23 |
r['decompression_time_ns_per_point'], r['original_size_bytes'],
|
| 24 |
+
r['compressed_size_bytes'], r.get('timing_column_count', 0),
|
| 25 |
+
indices['timing_aggregations'][r['timing_aggregation']]])
|
| 26 |
payload = {key: data[key] for key in ('schema_version','benchmark','coverage','datasets','methods','scopes','source')}
|
| 27 |
if 'dataset_summary' in data:
|
| 28 |
payload['dataset_summary'] = data['dataset_summary']
|
data.json
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:727bf6a91dbb2bc8f63dd87122b8dc1db261589e4da742f28f0e52dad0616571
|
| 3 |
+
size 41080819
|
export_results.py
CHANGED
|
@@ -74,6 +74,52 @@ def _finite(value: Any, *, positive: bool = False) -> float:
|
|
| 74 |
return number
|
| 75 |
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
@lru_cache(maxsize=None)
|
| 78 |
def _algorithm_metadata(algorithm_key: str) -> tuple[bool, str | None, bool]:
|
| 79 |
from myapp.home_leaderboard_boxplot_data import (
|
|
@@ -233,31 +279,9 @@ def _configuration_rows(
|
|
| 233 |
compressed_bytes = _finite(record.compressedSize, positive=True)
|
| 234 |
points = original_bytes / 8.0
|
| 235 |
timing_rows = work[
|
| 236 |
-
|
| 237 |
-
& (pd.to_numeric(work["column_index"], errors="coerce") >= 0)
|
| 238 |
].copy()
|
| 239 |
-
|
| 240 |
-
if timing_column_count:
|
| 241 |
-
timing_columns = timing_rows.groupby(
|
| 242 |
-
["_timing_source_type", "column_index"], as_index=False
|
| 243 |
-
).agg(
|
| 244 |
-
originalSize=("originalSize", "sum"),
|
| 245 |
-
compressionTime=("compressionTime", "sum"),
|
| 246 |
-
decompressionTime=("decompressionTime", "sum"),
|
| 247 |
-
)
|
| 248 |
-
timing_column_count = len(timing_columns)
|
| 249 |
-
timing_points = timing_columns["originalSize"] / 8.0
|
| 250 |
-
compression_time_ns_per_point = float(
|
| 251 |
-
(timing_columns["compressionTime"] / timing_points).mean()
|
| 252 |
-
)
|
| 253 |
-
decompression_time_ns_per_point = float(
|
| 254 |
-
(timing_columns["decompressionTime"] / timing_points).mean()
|
| 255 |
-
)
|
| 256 |
-
else:
|
| 257 |
-
# A column_index=-1 row is a whole-report aggregate. It cannot prove
|
| 258 |
-
# the requested arithmetic mean of individual column timings.
|
| 259 |
-
compression_time_ns_per_point = None
|
| 260 |
-
decompression_time_ns_per_point = None
|
| 261 |
rows.append(
|
| 262 |
{
|
| 263 |
"dataset": dataset_key,
|
|
@@ -273,9 +297,10 @@ def _configuration_rows(
|
|
| 273 |
"compression_time_ns": _finite(record.compressionTime),
|
| 274 |
"decompression_time_ns": _finite(record.decompressionTime),
|
| 275 |
"compression_rate": compressed_bytes / original_bytes,
|
| 276 |
-
"compression_time_ns_per_point":
|
| 277 |
-
"decompression_time_ns_per_point":
|
| 278 |
-
"timing_column_count":
|
|
|
|
| 279 |
}
|
| 280 |
)
|
| 281 |
return sorted(rows, key=lambda row: (row["method"], row["algorithm_variant"]))
|
|
@@ -357,24 +382,32 @@ def _aggregate_rows(
|
|
| 357 |
elapsed_point_sum = sum(row["point_count"] for row in elapsed_rows)
|
| 358 |
comp_time_sum = sum(row["compression_time_ns"] for row in elapsed_rows)
|
| 359 |
decomp_time_sum = sum(row["decompression_time_ns"] for row in elapsed_rows)
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
|
|
|
| 364 |
and row.get("decompression_time_ns_per_point") is not None
|
| 365 |
-
|
| 366 |
-
timing_column_count = sum(row["timing_column_count"] for row in timing_rows)
|
| 367 |
-
timing_complete = len(timing_rows) == len(rows)
|
| 368 |
-
average_compression_time = (
|
| 369 |
-
sum(row["compression_time_ns_per_point"] * row["timing_column_count"] for row in timing_rows)
|
| 370 |
-
/ timing_column_count
|
| 371 |
-
if timing_column_count and timing_complete else None
|
| 372 |
-
)
|
| 373 |
-
average_decompression_time = (
|
| 374 |
-
sum(row["decompression_time_ns_per_point"] * row["timing_column_count"] for row in timing_rows)
|
| 375 |
-
/ timing_column_count
|
| 376 |
-
if timing_column_count and timing_complete else None
|
| 377 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
return {
|
| 379 |
"runtime": runtime,
|
| 380 |
"scope": scope_key,
|
|
@@ -385,14 +418,16 @@ def _aggregate_rows(
|
|
| 385 |
"overall_compression_rate": compressed_sum / original_sum,
|
| 386 |
"average_compression_rate": sum(row["compression_rate"] for row in rows) / len(rows),
|
| 387 |
"weighted_compression_time_ns_per_point": (
|
| 388 |
-
comp_time_sum / elapsed_point_sum if elapsed_point_sum else None
|
| 389 |
),
|
| 390 |
"average_compression_time_ns_per_point": average_compression_time,
|
| 391 |
"weighted_decompression_time_ns_per_point": (
|
| 392 |
-
decomp_time_sum / elapsed_point_sum if elapsed_point_sum else None
|
| 393 |
),
|
| 394 |
"average_decompression_time_ns_per_point": average_decompression_time,
|
| 395 |
"timing_column_count": timing_column_count,
|
|
|
|
|
|
|
| 396 |
"original_size_bytes": original_sum,
|
| 397 |
"compressed_size_bytes": compressed_sum,
|
| 398 |
"point_count": point_sum,
|
|
@@ -527,7 +562,7 @@ def main() -> int:
|
|
| 527 |
"current_result_selection": "visible configurations of methods categorized as lossless-design by the project; result-level float round trips are not established",
|
| 528 |
"paper_result_selection": "the separate paper_table3 section contains its frozen 20-method C++ snapshot",
|
| 529 |
"scope_note": "Current result rows cover numeric int/float report evidence for the retained 19 public datasets. They reflect the columns present in each report; they do not assert full-column coverage beyond those files.",
|
| 530 |
-
"aggregation_note": "
|
| 531 |
"selection_note": "Configuration views retain measured configurations passing the project's method-name filter. This does not certify every result as lossless. Family views choose the lowest-rate configuration independently for each dataset, scope, and runtime.",
|
| 532 |
"notes": [
|
| 533 |
"Missing combinations are unavailable rather than zero.",
|
|
@@ -538,7 +573,7 @@ def main() -> int:
|
|
| 538 |
"compression_rate": "compressed bytes divided by original numeric bytes; lower is better",
|
| 539 |
"average_compression_rate": "arithmetic mean of per-dataset compression rates",
|
| 540 |
"overall_compression_rate": "sum of compressed bytes divided by sum of original numeric bytes",
|
| 541 |
-
"average_time_ns_per_point": "arithmetic mean of per-column nanoseconds per numeric point; legacy CSV
|
| 542 |
"weighted_time_ns_per_point": "sum of measured nanoseconds divided by sum of 8-byte numeric points",
|
| 543 |
"paper_median_balanced_score": "stored paper snapshot value; normalization is paper-scope specific and lower is better",
|
| 544 |
},
|
|
@@ -547,6 +582,7 @@ def main() -> int:
|
|
| 547 |
"No round-trip verification claim is exported from timing/result CSVs alone.",
|
| 548 |
"Family-level aggregates select the measured variant with the lowest compression rate within each dataset and method family, matching the backend family-selection rule.",
|
| 549 |
"dataset_results contains every visible measured configuration; is_best_rate_in_family marks the configuration used for family-level aggregation.",
|
|
|
|
| 550 |
"Paper Table 3 values and current report recomputations are separate result sets because the report tree has evolved since the paper snapshot was frozen.",
|
| 551 |
],
|
| 552 |
},
|
|
@@ -570,6 +606,16 @@ def main() -> int:
|
|
| 570 |
"configuration_aggregate_row_count": len(configuration_aggregates),
|
| 571 |
"family_best_aggregate_row_count": len(family_best_aggregates),
|
| 572 |
"dataset_result_row_count": len(dataset_rows),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
"source_report_file_count": len(report_files),
|
| 574 |
"missing_source_report_count": missing_report_count,
|
| 575 |
"excluded_datasets": dataset_scope["meta"].get("excluded_dataset_keys", []),
|
|
|
|
| 74 |
return number
|
| 75 |
|
| 76 |
|
| 77 |
+
def _timing_stats_from_report(rows: Any) -> dict[str, Any]:
|
| 78 |
+
"""Return a column mean or an explicit whole-dataset fallback."""
|
| 79 |
+
import pandas as pd
|
| 80 |
+
|
| 81 |
+
if rows is None or rows.empty:
|
| 82 |
+
return {"compression": None, "decompression": None, "column_count": 0,
|
| 83 |
+
"aggregation": "unavailable"}
|
| 84 |
+
work = rows.copy()
|
| 85 |
+
if work.get("_timing_source_type") is None:
|
| 86 |
+
work["_timing_source_type"] = "single_report"
|
| 87 |
+
column_groups = []
|
| 88 |
+
aggregate_groups = []
|
| 89 |
+
for source_type, source_rows in work.groupby("_timing_source_type", sort=True):
|
| 90 |
+
columns = source_rows[pd.to_numeric(source_rows["column_index"], errors="coerce") >= 0]
|
| 91 |
+
if not columns.empty:
|
| 92 |
+
grouped = columns.groupby("column_index", as_index=False).agg(
|
| 93 |
+
originalSize=("originalSize", "sum"),
|
| 94 |
+
compressionTime=("compressionTime", "sum"),
|
| 95 |
+
decompressionTime=("decompressionTime", "sum"),
|
| 96 |
+
)
|
| 97 |
+
grouped["_timing_source_type"] = source_type
|
| 98 |
+
column_groups.append(grouped)
|
| 99 |
+
else:
|
| 100 |
+
aggregate = source_rows[pd.to_numeric(source_rows["column_index"], errors="coerce") < 0]
|
| 101 |
+
if not aggregate.empty:
|
| 102 |
+
aggregate_groups.append(aggregate)
|
| 103 |
+
if column_groups and not aggregate_groups:
|
| 104 |
+
grouped = pd.concat(column_groups, ignore_index=True)
|
| 105 |
+
points = grouped["originalSize"] / 8.0
|
| 106 |
+
return {"compression": float((grouped["compressionTime"] / points).mean()),
|
| 107 |
+
"decompression": float((grouped["decompressionTime"] / points).mean()),
|
| 108 |
+
"column_count": int(len(grouped)), "aggregation": "column_mean"}
|
| 109 |
+
elapsed_parts = [*column_groups, *aggregate_groups]
|
| 110 |
+
if elapsed_parts:
|
| 111 |
+
# Use real columns for a typed report when present; use its -1 aggregate
|
| 112 |
+
# only when that typed report lacks column rows, avoiding double count.
|
| 113 |
+
elapsed = pd.concat(elapsed_parts, ignore_index=True)
|
| 114 |
+
points = float(elapsed["originalSize"].sum() / 8.0)
|
| 115 |
+
if points > 0:
|
| 116 |
+
return {"compression": float(elapsed["compressionTime"].sum()) / points,
|
| 117 |
+
"decompression": float(elapsed["decompressionTime"].sum()) / points,
|
| 118 |
+
"column_count": 0, "aggregation": "dataset_aggregate"}
|
| 119 |
+
return {"compression": None, "decompression": None, "column_count": 0,
|
| 120 |
+
"aggregation": "unavailable"}
|
| 121 |
+
|
| 122 |
+
|
| 123 |
@lru_cache(maxsize=None)
|
| 124 |
def _algorithm_metadata(algorithm_key: str) -> tuple[bool, str | None, bool]:
|
| 125 |
from myapp.home_leaderboard_boxplot_data import (
|
|
|
|
| 279 |
compressed_bytes = _finite(record.compressedSize, positive=True)
|
| 280 |
points = original_bytes / 8.0
|
| 281 |
timing_rows = work[
|
| 282 |
+
work["algorithm"].astype(str) == str(record.algorithm)
|
|
|
|
| 283 |
].copy()
|
| 284 |
+
timing = _timing_stats_from_report(timing_rows)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 285 |
rows.append(
|
| 286 |
{
|
| 287 |
"dataset": dataset_key,
|
|
|
|
| 297 |
"compression_time_ns": _finite(record.compressionTime),
|
| 298 |
"decompression_time_ns": _finite(record.decompressionTime),
|
| 299 |
"compression_rate": compressed_bytes / original_bytes,
|
| 300 |
+
"compression_time_ns_per_point": timing["compression"],
|
| 301 |
+
"decompression_time_ns_per_point": timing["decompression"],
|
| 302 |
+
"timing_column_count": timing["column_count"],
|
| 303 |
+
"timing_aggregation": timing["aggregation"],
|
| 304 |
}
|
| 305 |
)
|
| 306 |
return sorted(rows, key=lambda row: (row["method"], row["algorithm_variant"]))
|
|
|
|
| 382 |
elapsed_point_sum = sum(row["point_count"] for row in elapsed_rows)
|
| 383 |
comp_time_sum = sum(row["compression_time_ns"] for row in elapsed_rows)
|
| 384 |
decomp_time_sum = sum(row["decompression_time_ns"] for row in elapsed_rows)
|
| 385 |
+
elapsed_complete = len(elapsed_rows) == len(rows)
|
| 386 |
+
timing_column_count = sum(row.get("timing_column_count", 0) for row in rows)
|
| 387 |
+
modes = [row.get("timing_aggregation", "unavailable") for row in rows]
|
| 388 |
+
valid_times = all(
|
| 389 |
+
row.get("compression_time_ns_per_point") is not None
|
| 390 |
and row.get("decompression_time_ns_per_point") is not None
|
| 391 |
+
for row in rows
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
)
|
| 393 |
+
if not valid_times or "unavailable" in modes:
|
| 394 |
+
average_compression_time = average_decompression_time = None
|
| 395 |
+
timing_aggregation = "unavailable"
|
| 396 |
+
elif "dataset_aggregate" in modes:
|
| 397 |
+
average_compression_time = sum(row["compression_time_ns_per_point"] for row in rows) / len(rows)
|
| 398 |
+
average_decompression_time = sum(row["decompression_time_ns_per_point"] for row in rows) / len(rows)
|
| 399 |
+
timing_aggregation = "dataset_mean"
|
| 400 |
+
elif timing_column_count:
|
| 401 |
+
average_compression_time = sum(
|
| 402 |
+
row["compression_time_ns_per_point"] * row["timing_column_count"] for row in rows
|
| 403 |
+
) / timing_column_count
|
| 404 |
+
average_decompression_time = sum(
|
| 405 |
+
row["decompression_time_ns_per_point"] * row["timing_column_count"] for row in rows
|
| 406 |
+
) / timing_column_count
|
| 407 |
+
timing_aggregation = "column_mean"
|
| 408 |
+
else:
|
| 409 |
+
average_compression_time = average_decompression_time = None
|
| 410 |
+
timing_aggregation = "unavailable"
|
| 411 |
return {
|
| 412 |
"runtime": runtime,
|
| 413 |
"scope": scope_key,
|
|
|
|
| 418 |
"overall_compression_rate": compressed_sum / original_sum,
|
| 419 |
"average_compression_rate": sum(row["compression_rate"] for row in rows) / len(rows),
|
| 420 |
"weighted_compression_time_ns_per_point": (
|
| 421 |
+
comp_time_sum / elapsed_point_sum if elapsed_point_sum and elapsed_complete else None
|
| 422 |
),
|
| 423 |
"average_compression_time_ns_per_point": average_compression_time,
|
| 424 |
"weighted_decompression_time_ns_per_point": (
|
| 425 |
+
decomp_time_sum / elapsed_point_sum if elapsed_point_sum and elapsed_complete else None
|
| 426 |
),
|
| 427 |
"average_decompression_time_ns_per_point": average_decompression_time,
|
| 428 |
"timing_column_count": timing_column_count,
|
| 429 |
+
"timing_aggregation": timing_aggregation,
|
| 430 |
+
"timing_dataset_count": len(rows),
|
| 431 |
"original_size_bytes": original_sum,
|
| 432 |
"compressed_size_bytes": compressed_sum,
|
| 433 |
"point_count": point_sum,
|
|
|
|
| 562 |
"current_result_selection": "visible configurations of methods categorized as lossless-design by the project; result-level float round trips are not established",
|
| 563 |
"paper_result_selection": "the separate paper_table3 section contains its frozen 20-method C++ snapshot",
|
| 564 |
"scope_note": "Current result rows cover numeric int/float report evidence for the retained 19 public datasets. They reflect the columns present in each report; they do not assert full-column coverage beyond those files.",
|
| 565 |
+
"aggregation_note": "Dataset rows with column evidence use an arithmetic mean of per-column nanoseconds per point. Rows backed only by whole-report timing use source dataset elapsed time divided by source point totals and retain a zero column count. If any selected row uses that fallback, method timing is an equal-dataset arithmetic mean; otherwise it is pooled equally over measured columns.",
|
| 566 |
"selection_note": "Configuration views retain measured configurations passing the project's method-name filter. This does not certify every result as lossless. Family views choose the lowest-rate configuration independently for each dataset, scope, and runtime.",
|
| 567 |
"notes": [
|
| 568 |
"Missing combinations are unavailable rather than zero.",
|
|
|
|
| 573 |
"compression_rate": "compressed bytes divided by original numeric bytes; lower is better",
|
| 574 |
"average_compression_rate": "arithmetic mean of per-dataset compression rates",
|
| 575 |
"overall_compression_rate": "sum of compressed bytes divided by sum of original numeric bytes",
|
| 576 |
+
"average_time_ns_per_point": "column-backed rows use an arithmetic mean of per-column nanoseconds per numeric point; whole-report-only rows use source elapsed nanoseconds divided by source point totals; legacy CSV rows retain their 8-byte-equivalent point denominator",
|
| 577 |
"weighted_time_ns_per_point": "sum of measured nanoseconds divided by sum of 8-byte numeric points",
|
| 578 |
"paper_median_balanced_score": "stored paper snapshot value; normalization is paper-scope specific and lower is better",
|
| 579 |
},
|
|
|
|
| 582 |
"No round-trip verification claim is exported from timing/result CSVs alone.",
|
| 583 |
"Family-level aggregates select the measured variant with the lowest compression rate within each dataset and method family, matching the backend family-selection rule.",
|
| 584 |
"dataset_results contains every visible measured configuration; is_best_rate_in_family marks the configuration used for family-level aggregation.",
|
| 585 |
+
"Whole-report timing rows (column_index=-1) remain dataset-level timing evidence with timing_column_count=0; they are never treated as columns.",
|
| 586 |
"Paper Table 3 values and current report recomputations are separate result sets because the report tree has evolved since the paper snapshot was frozen.",
|
| 587 |
],
|
| 588 |
},
|
|
|
|
| 606 |
"configuration_aggregate_row_count": len(configuration_aggregates),
|
| 607 |
"family_best_aggregate_row_count": len(family_best_aggregates),
|
| 608 |
"dataset_result_row_count": len(dataset_rows),
|
| 609 |
+
"timing_column_observation_count": sum(row["timing_column_count"] for row in dataset_rows),
|
| 610 |
+
"timing_column_mean_dataset_result_count": sum(
|
| 611 |
+
row["timing_aggregation"] == "column_mean" for row in dataset_rows
|
| 612 |
+
),
|
| 613 |
+
"timing_dataset_aggregate_result_count": sum(
|
| 614 |
+
row["timing_aggregation"] == "dataset_aggregate" for row in dataset_rows
|
| 615 |
+
),
|
| 616 |
+
"timing_unavailable_dataset_result_count": sum(
|
| 617 |
+
row["timing_aggregation"] == "unavailable" for row in dataset_rows
|
| 618 |
+
),
|
| 619 |
"source_report_file_count": len(report_files),
|
| 620 |
"missing_source_report_count": missing_report_count,
|
| 621 |
"excluded_datasets": dataset_scope["meta"].get("excluded_dataset_keys", []),
|
index.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
| 7 |
<meta name="color-scheme" content="light dark">
|
| 8 |
<title>THULab | Time Series Compression Benchmark</title>
|
| 9 |
<link rel="stylesheet" href="style.css?v=20261009-dbp-integrated-v1">
|
| 10 |
-
<script src="app.js?v=20261009-
|
| 11 |
</head>
|
| 12 |
<body>
|
| 13 |
<a class="skip-link" href="#content">Skip to results</a>
|
|
@@ -62,7 +62,7 @@
|
|
| 62 |
<div><h2 id="view-title">Overall leaderboard</h2><p id="selection-summary" class="muted" aria-live="polite">Reading published results…</p></div>
|
| 63 |
<div class="toolbar-actions"><button id="reset" class="quiet-button">Reset filters</button><button id="download" class="primary-button" disabled>Download CSV</button></div>
|
| 64 |
</div>
|
| 65 |
-
<div class="results-note" id="results-note">Compression rate = compressed bytes / original bytes. Lower rates and lower ns/point are better. Compression and decompression costs
|
| 66 |
<div id="score-controls" class="score-controls">
|
| 67 |
<label>Score weights · a: rate / b: compress / c: decompress<select id="weights" aria-label="Score weights a b c"></select></label>
|
| 68 |
<p id="score-note" class="muted" aria-live="polite">Non-negative weights in steps of 0.1, summing to 1.0.</p>
|
|
@@ -108,7 +108,7 @@
|
|
| 108 |
<dl class="definitions">
|
| 109 |
<div><dt>Average compression rate ↓</dt><dd>Arithmetic mean of the per-dataset compression rates in the selected scope.</dd></div>
|
| 110 |
<div><dt>Overall compression rate ↓</dt><dd>Total compressed bytes divided by total original bytes over the selected measured records.</dd></div>
|
| 111 |
-
<div><dt>Compression / decompression cost ↓</dt><dd>For each result with column-level timing evidence, calculate ns/point independently for every usable numeric column, then take the arithmetic mean across those columns. Each column contributes equally. Overall timing pools all measured columns across the selected datasets
|
| 112 |
<div><dt>Coverage</dt><dd>Datasets with usable measurements for a method out of the measured datasets in the selected runtime, data type, and dataset selection. The summary dataset count uses the same selection. Missing results are never filled with zero.</dd></div>
|
| 113 |
<div><dt>Composite score ↓</dt><dd>a × average compression rate + b × normalized average compression time + c × normalized average decompression time. Each time uses min–max over all measured rows in the selected runtime, scope and row mode, before search, family and coverage filters. If all times are equal, their normalized value is zero. All measured inputs must have usable timing metrics.</dd></div>
|
| 114 |
<div><dt>Average Rank ↓</dt><dd>Compute the same weighted score within each dataset, normalizing times within that dataset. Rank lower scores first; ties share their average position. Then take the arithmetic mean of the method's available dataset ranks. Weights are non-negative tenths summing to 1.0. Missing measurements do not receive ranks.</dd></div>
|
|
|
|
| 7 |
<meta name="color-scheme" content="light dark">
|
| 8 |
<title>THULab | Time Series Compression Benchmark</title>
|
| 9 |
<link rel="stylesheet" href="style.css?v=20261009-dbp-integrated-v1">
|
| 10 |
+
<script src="app.js?v=20261009-dataset-fallback-v1" type="module"></script>
|
| 11 |
</head>
|
| 12 |
<body>
|
| 13 |
<a class="skip-link" href="#content">Skip to results</a>
|
|
|
|
| 62 |
<div><h2 id="view-title">Overall leaderboard</h2><p id="selection-summary" class="muted" aria-live="polite">Reading published results…</p></div>
|
| 63 |
<div class="toolbar-actions"><button id="reset" class="quiet-button">Reset filters</button><button id="download" class="primary-button" disabled>Download CSV</button></div>
|
| 64 |
</div>
|
| 65 |
+
<div class="results-note" id="results-note">Compression rate = compressed bytes / original bytes. Lower rates and lower ns/point are better. Compression and decompression costs use equal-column arithmetic means where column timings are available. Methods with aggregate-only timings use equal-dataset arithmetic means for the selected range.</div>
|
| 66 |
<div id="score-controls" class="score-controls">
|
| 67 |
<label>Score weights · a: rate / b: compress / c: decompress<select id="weights" aria-label="Score weights a b c"></select></label>
|
| 68 |
<p id="score-note" class="muted" aria-live="polite">Non-negative weights in steps of 0.1, summing to 1.0.</p>
|
|
|
|
| 108 |
<dl class="definitions">
|
| 109 |
<div><dt>Average compression rate ↓</dt><dd>Arithmetic mean of the per-dataset compression rates in the selected scope.</dd></div>
|
| 110 |
<div><dt>Overall compression rate ↓</dt><dd>Total compressed bytes divided by total original bytes over the selected measured records.</dd></div>
|
| 111 |
+
<div><dt>Compression / decompression cost ↓</dt><dd>For each result with column-level timing evidence, calculate ns/point independently for every usable numeric column, then take the arithmetic mean across those columns. Each column contributes equally. Overall timing pools all measured columns across the selected datasets when every selected dataset has column timings. If any selected dataset/configuration has only aggregate timing, use the arithmetic mean of the selected datasets' ns/point values instead, giving each dataset equal weight. For an aggregate-only dataset, ns/point comes from its recorded total elapsed time divided by its recorded point count. Truly missing measurements remain unavailable. Method details and CSV identify the timing basis. Native-float measurements use valid native values; historical imported rows retain their source 8-byte-equivalent point definition. Compare timings within the same runtime and measurement contract.</dd></div>
|
| 112 |
<div><dt>Coverage</dt><dd>Datasets with usable measurements for a method out of the measured datasets in the selected runtime, data type, and dataset selection. The summary dataset count uses the same selection. Missing results are never filled with zero.</dd></div>
|
| 113 |
<div><dt>Composite score ↓</dt><dd>a × average compression rate + b × normalized average compression time + c × normalized average decompression time. Each time uses min–max over all measured rows in the selected runtime, scope and row mode, before search, family and coverage filters. If all times are equal, their normalized value is zero. All measured inputs must have usable timing metrics.</dd></div>
|
| 114 |
<div><dt>Average Rank ↓</dt><dd>Compute the same weighted score within each dataset, normalizing times within that dataset. Rank lower scores first; ties share their average position. Then take the arithmetic mean of the method's available dataset ranks. Weights are non-negative tenths summing to 1.0. Missing measurements do not receive ranks.</dd></div>
|
manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
"catalog_dataset_count": 169,
|
| 4 |
"configuration_aggregate_row_count": 4653,
|
| 5 |
"dataset_count": 169,
|
| 6 |
-
"dataset_result_row_count":
|
| 7 |
"excluded_datasets": [
|
| 8 |
"Arade",
|
| 9 |
"poisson_timestamps",
|
|
@@ -26,12 +26,13 @@
|
|
| 26 |
],
|
| 27 |
"scope_count": 5,
|
| 28 |
"source_report_file_count": 108,
|
| 29 |
-
"timing_column_mean_dataset_result_count":
|
| 30 |
-
"timing_column_observation_count":
|
| 31 |
-
"
|
|
|
|
| 32 |
},
|
| 33 |
"data_file": "data.json",
|
| 34 |
-
"data_sha256": "
|
| 35 |
"dataset_catalog_sha256": "d69abc85742dc050e4cdab1e5a03fd3392a0e0f1964b2a88ca87ba7f768b7385",
|
| 36 |
"excluded_content": [
|
| 37 |
"raw datasets",
|
|
@@ -207,6 +208,64 @@
|
|
| 207 |
"source_scope_sha256": "0fabc01f25d62ddb49585b3208103543b16c6e50340195360a0516411fa148b4",
|
| 208 |
"source_sha256": "febe0d4494cf3778bb3e386ac8674f24406e29d1d7d9b47bd834b332b0e201fb",
|
| 209 |
"verified_column_count_per_runtime": 4096
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
}
|
| 211 |
],
|
| 212 |
"result_csv_files": [
|
|
@@ -767,14 +826,15 @@
|
|
| 767 |
}
|
| 768 |
],
|
| 769 |
"timing_recalculation": {
|
| 770 |
-
"
|
| 771 |
"dbp_float_audit_path": "analysis_outputs/dbp_float_e2e_20261009/publish_payload/dbp-audit.json",
|
| 772 |
"dbp_float_audit_sha256": "febe0d4494cf3778bb3e386ac8674f24406e29d1d7d9b47bd834b332b0e201fb",
|
| 773 |
"dbp_precision_source_file_count": 376,
|
| 774 |
"dbp_precision_source_hash_status": "all_match",
|
| 775 |
-
"generated_at": "2026-10-
|
| 776 |
-
"policy": "
|
| 777 |
"result_csv_file_count": 108,
|
| 778 |
-
"result_csv_sha256_status": "all_match"
|
|
|
|
| 779 |
}
|
| 780 |
}
|
|
|
|
| 3 |
"catalog_dataset_count": 169,
|
| 4 |
"configuration_aggregate_row_count": 4653,
|
| 5 |
"dataset_count": 169,
|
| 6 |
+
"dataset_result_row_count": 65223,
|
| 7 |
"excluded_datasets": [
|
| 8 |
"Arade",
|
| 9 |
"poisson_timestamps",
|
|
|
|
| 26 |
],
|
| 27 |
"scope_count": 5,
|
| 28 |
"source_report_file_count": 108,
|
| 29 |
+
"timing_column_mean_dataset_result_count": 64771,
|
| 30 |
+
"timing_column_observation_count": 1435347,
|
| 31 |
+
"timing_dataset_aggregate_result_count": 452,
|
| 32 |
+
"timing_unavailable_dataset_result_count": 0
|
| 33 |
},
|
| 34 |
"data_file": "data.json",
|
| 35 |
+
"data_sha256": "727bf6a91dbb2bc8f63dd87122b8dc1db261589e4da742f28f0e52dad0616571",
|
| 36 |
"dataset_catalog_sha256": "d69abc85742dc050e4cdab1e5a03fd3392a0e0f1964b2a88ca87ba7f768b7385",
|
| 37 |
"excluded_content": [
|
| 38 |
"raw datasets",
|
|
|
|
| 208 |
"source_scope_sha256": "0fabc01f25d62ddb49585b3208103543b16c6e50340195360a0516411fa148b4",
|
| 209 |
"source_sha256": "febe0d4494cf3778bb3e386ac8674f24406e29d1d7d9b47bd834b332b0e201fb",
|
| 210 |
"verified_column_count_per_runtime": 4096
|
| 211 |
+
},
|
| 212 |
+
{
|
| 213 |
+
"benchmark_contract": {
|
| 214 |
+
"block_state": "reset for every frozen logical block",
|
| 215 |
+
"codec": "project delta + ZigZag + ULEB128 int64 wire",
|
| 216 |
+
"column_count": 1,
|
| 217 |
+
"cpu_affinity": [
|
| 218 |
+
37
|
| 219 |
+
],
|
| 220 |
+
"governor": "schedutil",
|
| 221 |
+
"logical_blocks": 10,
|
| 222 |
+
"method": "DELTA_BINARY_PACKED",
|
| 223 |
+
"repetitions": 1,
|
| 224 |
+
"shared_server": true,
|
| 225 |
+
"timing": "encode and decode timed per block; block nanoseconds summed",
|
| 226 |
+
"timing_aggregation": "column_mean",
|
| 227 |
+
"warmup": "first min(20, logical_block_count) blocks once, metrics discarded",
|
| 228 |
+
"warmup_blocks_executed": 10
|
| 229 |
+
},
|
| 230 |
+
"cross_runtime_golden": {
|
| 231 |
+
"all_runtime_compressed_size_bytes": 615712,
|
| 232 |
+
"all_runtime_decoded_i64le_sha256": "17bd25237309c72cad7b34fa255fd508c5c4b8ce79423e79438d5a8212a68c8b",
|
| 233 |
+
"all_runtime_payload_sha256": "39214295d7739f2417d73b4cc9bb8771a228268500f3dab5a03eacdf7b4aea23",
|
| 234 |
+
"historical_java_compressed_size_bytes": 615712,
|
| 235 |
+
"status": "passed"
|
| 236 |
+
},
|
| 237 |
+
"dataset": "medium_posts",
|
| 238 |
+
"environment": {
|
| 239 |
+
"cpu37_no_user_process_before_after": true,
|
| 240 |
+
"cpu37_processes_after_sha256": "7fcee621228a258ad0262e0bd4c7c3eb8f2452d685982e520a52a2b41cc01816",
|
| 241 |
+
"cpu37_processes_before_sha256": "7fcee621228a258ad0262e0bd4c7c3eb8f2452d685982e520a52a2b41cc01816",
|
| 242 |
+
"cpu_model": "AMD EPYC 7542 32-Core Processor",
|
| 243 |
+
"gxx": "g++ (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0",
|
| 244 |
+
"hostname": "server",
|
| 245 |
+
"java": "openjdk version \"17.0.16\" 2025-07-15",
|
| 246 |
+
"kernel": "5.15.0-152-generic",
|
| 247 |
+
"machine": "x86_64",
|
| 248 |
+
"python": "3.10.12"
|
| 249 |
+
},
|
| 250 |
+
"family": "DBP",
|
| 251 |
+
"integrated_at": "2026-10-09T07:25:05.180457+00:00",
|
| 252 |
+
"integration_payload_path": "analysis_outputs/column_mean_20261009/dbp_medium_posts_retest/integration_payload.json",
|
| 253 |
+
"integration_payload_sha256": "e45170a955d1cd0df50dba25f9e41f24f00fc8b559e702d59188b6cfa60c99dc",
|
| 254 |
+
"measurement_receipt_path": "analysis_outputs/column_mean_20261009/dbp_medium_posts_retest/measurement_receipt.json",
|
| 255 |
+
"method": "DELTA_BINARY_PACKED",
|
| 256 |
+
"runtimes": [
|
| 257 |
+
"cpp",
|
| 258 |
+
"java",
|
| 259 |
+
"python"
|
| 260 |
+
],
|
| 261 |
+
"scopes": [
|
| 262 |
+
"integer",
|
| 263 |
+
"overall"
|
| 264 |
+
],
|
| 265 |
+
"source_sha256": "10359f6f1153655710f7ce9b59d04e5460babe5606487b7794a47ba874ef4324",
|
| 266 |
+
"timing_aggregation": "column_mean",
|
| 267 |
+
"timing_column_count_per_row": 1,
|
| 268 |
+
"validation_status": "passed_byte_for_byte_lossless"
|
| 269 |
}
|
| 270 |
],
|
| 271 |
"result_csv_files": [
|
|
|
|
| 826 |
}
|
| 827 |
],
|
| 828 |
"timing_recalculation": {
|
| 829 |
+
"aggregate_only_dataset_fallback_row_count": 452,
|
| 830 |
"dbp_float_audit_path": "analysis_outputs/dbp_float_e2e_20261009/publish_payload/dbp-audit.json",
|
| 831 |
"dbp_float_audit_sha256": "febe0d4494cf3778bb3e386ac8674f24406e29d1d7d9b47bd834b332b0e201fb",
|
| 832 |
"dbp_precision_source_file_count": 376,
|
| 833 |
"dbp_precision_source_hash_status": "all_match",
|
| 834 |
+
"generated_at": "2026-10-09T07:25:05.180457+00:00",
|
| 835 |
+
"policy": "column_mean_with_dataset_aggregate_fallback",
|
| 836 |
"result_csv_file_count": 108,
|
| 837 |
+
"result_csv_sha256_status": "all_match",
|
| 838 |
+
"timing_unavailable_row_count": 0
|
| 839 |
}
|
| 840 |
}
|
ui-data.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|