Spaces:
Running
Running
Show provisional Composite scores from current admitted results
Browse filesUse the current published C++ measurements to display all 85 Composite scores with default weights 0.4/0.3/0.3. LZG uses its admitted 134/135 timing subset until the final measurement is available. Keep scientific payloads, Average Rank rules, and strict full-coverage timing unchanged.
- app.js +12 -9
- availability.js +6 -1
- index.html +4 -4
- ranking.js +50 -5
app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import {FINAL160_SCOPE,FINAL160_INPUT_STATUS,applyFinal160Scope,filterFinal160Catalog,final160CoverageForFamily} from './final-scope.js?v=20261013-min128-v1';
|
| 2 |
-
import {WEIGHT_TENTHS,parseWeights,addRankingMetrics} from './ranking.js?v=
|
| 3 |
-
import {DEFAULT_PROFILE,profileLabel,defaultColumnVisible,metricAvailability,summarizeAvailability,visibleColumns,profileScopeText,aggregateTimedSubset,strictTimingMode} from './availability.js?v=
|
| 4 |
const UI_DATA_SHA256='ffd11d5c9a863ca412948c6936b4058b46db9f01f48b738ec0b81ef19bf3f1e6';
|
| 5 |
const UI_DATA_GZIP_SHA256='f16a98d8d4438186dfa9a7ebb196f46069b0f722cdb430b1673fb69c8284bbc3';
|
| 6 |
const CPP_LATEST_VIEW_SHA256='6ab4cc1e9e788f5baac4d79a8584ff647e3a6d7451d57a8a1fc1943502b7b2b7';
|
|
@@ -98,7 +98,7 @@ function aggregate(input) {
|
|
| 98 |
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+(Number.isInteger(r.timing_column_count)?r.timing_column_count:0),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,...timedSubset});
|
| 99 |
}
|
| 100 |
const s=state();
|
| 101 |
-
return addRankingMetrics(rows,parseWeights($('weights').value)).map(row=>row.normalization_reference_rows>=2?row:{...row,normalized_compression_time:null,normalized_decompression_time:null,composite_score:null}).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)=>{
|
| 102 |
const av=number(a[sort.key]),bv=number(b[sort.key]);
|
| 103 |
if(av===null&&bv===null)return a.method.localeCompare(b.method);
|
| 104 |
if(av===null)return 1;if(bv===null)return -1;
|
|
@@ -119,7 +119,8 @@ function metricCell(row,column) {
|
|
| 119 |
if(column.key==='rank_coverage'&&number(row[column.key])!==null)return `${row.rank_coverage} / ${row.totalDatasets}`;
|
| 120 |
if(number(row[column.key])!==null){
|
| 121 |
const subset=['compression_time_timed_subset','decompression_time_timed_subset'].includes(column.key);
|
| 122 |
-
|
|
|
|
| 123 |
}
|
| 124 |
const unavailable=metricAvailability(row,column.key);
|
| 125 |
return `<span class="unavailable-value" title="${escape(unavailable.detail)}">${escape(unavailable.short)}</span>`;
|
|
@@ -154,8 +155,9 @@ function refresh() {
|
|
| 154 |
syncColumnOptions();
|
| 155 |
const weights=parseWeights($('weights').value);
|
| 156 |
const scoreAvailability=summarizeAvailability(currentRows,cols);
|
| 157 |
-
const
|
| 158 |
-
|
|
|
|
| 159 |
const s=state(),scope=scopeKey(),measuredCount=coverageDatasetCount(),ds=s.dataset==='all'?`all ${measuredCount} measured datasets`:datasetDisplayName(s.dataset);
|
| 160 |
$('dataset-count').textContent=countFmt(measuredCount);$('dataset-count-label').textContent='measured datasets';
|
| 161 |
$('method-count').textContent=countFmt(new Set(records.filter(record=>record.runtime===s.runtime&&record.scope===scope).map(record=>record.family)).size);
|
|
@@ -193,7 +195,8 @@ function showMethod(method,focus=false) {
|
|
| 193 |
const supportNote=supportDecisions.length?`C++ test scope: ${supportDecisions.length} dataset identities; ${countSupport(item=>item.status==='numeric'&&item.scopes.includes('overall'))} full numeric Overall, ${countSupport(item=>item.status==='partial_numeric')} partial numeric (exact supported subset), ${countSupport(item=>item.status==='numeric'&&!item.scopes.includes('overall'))} full numeric type-specific only, ${countSupport(item=>item.status==='not_applicable')} not applicable, ${countSupport(item=>item.status==='unsupported')} unsupported, ${countSupport(item=>item.status==='replacement_input_pending')} corrected-input retests pending. Type-specific results are available through the data-type filter; they are not missing experiments.`:'';
|
| 194 |
|
| 195 |
const strictCompress=metricCell(row,cols.find(column=>column.key==='compression_time')),strictDecompress=metricCell(row,cols.find(column=>column.key==='decompression_time')),subsetCompress=metricCell(row,cols.find(column=>column.key==='compression_time_timed_subset')),subsetDecompress=metricCell(row,cols.find(column=>column.key==='decompression_time_timed_subset'));
|
| 196 |
-
|
|
|
|
| 197 |
detail.hidden=false;$('close-detail').addEventListener('click',()=>{detail.hidden=true;selectedMethod=null;});
|
| 198 |
if(focus){detail.scrollIntoView({block:'nearest',behavior:'auto'});detail.focus({preventScroll:true});}
|
| 199 |
}
|
|
@@ -217,8 +220,8 @@ function renderChart() {
|
|
| 217 |
function csv() {
|
| 218 |
const quote=v=>{let text=String(v??'');if(typeof v==='string'&&/^[=+@-]/.test(text))text="'"+text;return `"${text.replace(/"/g,'""')}"`;};
|
| 219 |
const weights=parseWeights($('weights').value);
|
| 220 |
-
const columns=['position','method','comparison_profile','execution_host','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','source_profile_by_dataset','binary_sha256_by_dataset','eligible_column_set_sha256_by_dataset','measurement_status_by_dataset','timing_profile_status_by_dataset','timing_column_count','timing_aggregation','timed_subset_compress_ns_per_point','timed_subset_decompress_ns_per_point','timed_subset_dataset_coverage','timed_subset_dataset_denominator','timed_subset_status','timed_subset_source_profiles','timed_subset_source_hosts','selected_source_family_by_dataset','selected_source_comparison_profile_by_dataset','selected_source_host_by_dataset','strict_timing_reason','composite_reason','final_dataset_scope','input_version_gate','pending_replacement_datasets'];
|
| 221 |
-
const body=currentRows.map((r,i)=>[i+1,r.method,r.runtime,runtimeHost(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
|
| 222 |
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);
|
| 223 |
}
|
| 224 |
function safeHttpUrl(value) {
|
|
|
|
| 1 |
import {FINAL160_SCOPE,FINAL160_INPUT_STATUS,applyFinal160Scope,filterFinal160Catalog,final160CoverageForFamily} from './final-scope.js?v=20261013-min128-v1';
|
| 2 |
+
import {WEIGHT_TENTHS,parseWeights,addRankingMetrics} from './ranking.js?v=20261016-provisional-current-timing-v1';
|
| 3 |
+
import {DEFAULT_PROFILE,profileLabel,defaultColumnVisible,metricAvailability,summarizeAvailability,visibleColumns,profileScopeText,aggregateTimedSubset,strictTimingMode} from './availability.js?v=20261016-provisional-current-timing-v1';
|
| 4 |
const UI_DATA_SHA256='ffd11d5c9a863ca412948c6936b4058b46db9f01f48b738ec0b81ef19bf3f1e6';
|
| 5 |
const UI_DATA_GZIP_SHA256='f16a98d8d4438186dfa9a7ebb196f46069b0f722cdb430b1673fb69c8284bbc3';
|
| 6 |
const CPP_LATEST_VIEW_SHA256='6ab4cc1e9e788f5baac4d79a8584ff647e3a6d7451d57a8a1fc1943502b7b2b7';
|
|
|
|
| 98 |
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+(Number.isInteger(r.timing_column_count)?r.timing_column_count:0),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,...timedSubset});
|
| 99 |
}
|
| 100 |
const s=state();
|
| 101 |
+
return addRankingMetrics(rows,parseWeights($('weights').value),{provisionalCurrentTiming:s.runtime==='cpp'}).map(row=>row.normalization_reference_rows>=2?row:{...row,normalized_compression_time:null,normalized_decompression_time:null,composite_score:null}).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)=>{
|
| 102 |
const av=number(a[sort.key]),bv=number(b[sort.key]);
|
| 103 |
if(av===null&&bv===null)return a.method.localeCompare(b.method);
|
| 104 |
if(av===null)return 1;if(bv===null)return -1;
|
|
|
|
| 119 |
if(column.key==='rank_coverage'&&number(row[column.key])!==null)return `${row.rank_coverage} / ${row.totalDatasets}`;
|
| 120 |
if(number(row[column.key])!==null){
|
| 121 |
const subset=['compression_time_timed_subset','decompression_time_timed_subset'].includes(column.key);
|
| 122 |
+
const provisional=column.key==='composite_score'&&row.composite_score_status==='provisional_current_admitted_timing';
|
| 123 |
+
return `${fmt(row[column.key],column.digits)}${subset?` <span class="metric-coverage" title="Timed subset coverage">${row.timing_subset_coverage} / ${row.timing_subset_denominator}</span>`:provisional?` <span class="metric-coverage" title="Provisional score: all current rate datasets plus admitted timing available now">provisional Β· timing ${row.composite_timing_coverage} / ${row.composite_timing_denominator}</span>`:''}`;
|
| 124 |
}
|
| 125 |
const unavailable=metricAvailability(row,column.key);
|
| 126 |
return `<span class="unavailable-value" title="${escape(unavailable.detail)}">${escape(unavailable.short)}</span>`;
|
|
|
|
| 155 |
syncColumnOptions();
|
| 156 |
const weights=parseWeights($('weights').value);
|
| 157 |
const scoreAvailability=summarizeAvailability(currentRows,cols);
|
| 158 |
+
const provisionalRows=currentRows.filter(row=>row.composite_score_status==='provisional_current_admitted_timing');
|
| 159 |
+
const scoreStatus=!currentRows.length?'No candidate rows are visible; comparability is not inferred.':provisionalRows.length===currentRows.length?`${provisionalRows.length}/${currentRows.length} provisional scores use every method's current rate coverage and its currently admitted timing coverage.`:scoreAvailability.counts.composite_score===currentRows.length?'Composite scores use one complete exact dataset/support signature.':`Composite scores are unavailable for ${currentRows.length-scoreAvailability.counts.composite_score}/${currentRows.length} rows because a positively weighted metric is missing.`;
|
| 160 |
+
$('score-note').textContent=`Score = ${weights[0].toFixed(1)} Γ average rate + ${weights[1].toFixed(1)} Γ normalized compress + ${weights[2].toFixed(1)} Γ normalized decompress. Lower is better. ${scoreStatus} Weights remain fixed and are not renormalized; a zero-weight metric is not required. Provisional C++ timing coverage is shown beside each score and in CSV. Average Rank keeps the matched dataset/support rule; missing, N/A, failed, and unlike-support results receive no rank.`;
|
| 161 |
const s=state(),scope=scopeKey(),measuredCount=coverageDatasetCount(),ds=s.dataset==='all'?`all ${measuredCount} measured datasets`:datasetDisplayName(s.dataset);
|
| 162 |
$('dataset-count').textContent=countFmt(measuredCount);$('dataset-count-label').textContent='measured datasets';
|
| 163 |
$('method-count').textContent=countFmt(new Set(records.filter(record=>record.runtime===s.runtime&&record.scope===scope).map(record=>record.family)).size);
|
|
|
|
| 195 |
const supportNote=supportDecisions.length?`C++ test scope: ${supportDecisions.length} dataset identities; ${countSupport(item=>item.status==='numeric'&&item.scopes.includes('overall'))} full numeric Overall, ${countSupport(item=>item.status==='partial_numeric')} partial numeric (exact supported subset), ${countSupport(item=>item.status==='numeric'&&!item.scopes.includes('overall'))} full numeric type-specific only, ${countSupport(item=>item.status==='not_applicable')} not applicable, ${countSupport(item=>item.status==='unsupported')} unsupported, ${countSupport(item=>item.status==='replacement_input_pending')} corrected-input retests pending. Type-specific results are available through the data-type filter; they are not missing experiments.`:'';
|
| 196 |
|
| 197 |
const strictCompress=metricCell(row,cols.find(column=>column.key==='compression_time')),strictDecompress=metricCell(row,cols.find(column=>column.key==='decompression_time')),subsetCompress=metricCell(row,cols.find(column=>column.key==='compression_time_timed_subset')),subsetDecompress=metricCell(row,cols.find(column=>column.key==='decompression_time_timed_subset'));
|
| 198 |
+
const detailTimingNote=row.runtime==='cpp'?'The provisional C++ composite uses the currently admitted timing subset and shows its coverage; strict timing remains unavailable until all selected rate datasets are timed. Dataset-level Average Rank still uses exact matched support.':'Composite scores keep the strict complete-support rule. Dataset-level Average Rank uses exact matched support.';
|
| 199 |
+
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>${strictCompress}</strong><span>strict Compress ns/point</span></div><div><strong>${strictDecompress}</strong><span>strict Decompress ns/point</span></div><div><strong>${subsetCompress}</strong><span>Compress ns/point Β· timed subset</span></div><div><strong>${subsetDecompress}</strong><span>Decompress ns/point Β· timed subset</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>`:''}${supportNote?`<p class="notice">${escape(supportNote)}</p>`:''}<p class="muted">Strict timing average: ${escape(timingLabel(row.timing_aggregation))}. ${escape(detailTimingNote)} Dataset metrics below retain the winning row's source family, profile, and host.</p><div class="detail-table"><table><thead><tr><th>Dataset</th><th>Configuration</th><th>Source family</th><th>Rate β</th><th>Compress ns/point β</th><th>Decompress ns/point β</th><th>Timing basis</th><th>Measurement evidence</th><th>Timing profile</th><th>Selected source profile / host</th><th>Runtime / binary</th><th>Support set</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>${escape(r.source_family??r.family)}</td><td class="numeric">${fmt(r.compression_rate,4)}</td><td class="numeric">${metricCell(r,cols.find(column=>column.key==='compression_time'))}</td><td class="numeric">${metricCell(r,cols.find(column=>column.key==='decompression_time'))}</td><td>${escape(timingLabel(r.timing_aggregation))}</td><td>${escape(r.measurement_status)}</td><td>${escape(r.timing_profile_status)}</td><td class="source-code">${escape(r.source_comparison_profile??r.runtime)} / ${escape(r.source_execution_host??'source snapshot')}</td><td class="source-code">${escape(r.source_runtime)} / ${escape(String(r.binary_sha256).slice(0,16))}</td><td class="source-code">${escape(String(r.eligible_column_set_sha256).slice(0,16))}</td><td class="numeric">${fmt(r.original_bytes,0)}</td><td class="numeric">${fmt(r.compressed_bytes,0)}</td><td class="numeric">${metricCell(r,{key:'dataset_score',digits:4})}</td><td class="numeric">${metricCell(r,{key:'dataset_rank',digits:2})}</td><td class="numeric">${fmt(r.dataset_candidate_count,0)}</td></tr>`).join('')}</tbody></table></div>`;
|
| 200 |
detail.hidden=false;$('close-detail').addEventListener('click',()=>{detail.hidden=true;selectedMethod=null;});
|
| 201 |
if(focus){detail.scrollIntoView({block:'nearest',behavior:'auto'});detail.focus({preventScroll:true});}
|
| 202 |
}
|
|
|
|
| 220 |
function csv() {
|
| 221 |
const quote=v=>{let text=String(v??'');if(typeof v==='string'&&/^[=+@-]/.test(text))text="'"+text;return `"${text.replace(/"/g,'""')}"`;};
|
| 222 |
const weights=parseWeights($('weights').value);
|
| 223 |
+
const columns=['position','method','comparison_profile','execution_host','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','composite_score_status','composite_rate_dataset_coverage','composite_timing_dataset_coverage','composite_timing_dataset_denominator','composite_metric_basis','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','source_profile_by_dataset','binary_sha256_by_dataset','eligible_column_set_sha256_by_dataset','measurement_status_by_dataset','timing_profile_status_by_dataset','timing_column_count','timing_aggregation','timed_subset_compress_ns_per_point','timed_subset_decompress_ns_per_point','timed_subset_dataset_coverage','timed_subset_dataset_denominator','timed_subset_status','timed_subset_source_profiles','timed_subset_source_hosts','selected_source_family_by_dataset','selected_source_comparison_profile_by_dataset','selected_source_host_by_dataset','strict_timing_reason','composite_reason','final_dataset_scope','input_version_gate','pending_replacement_datasets'];
|
| 224 |
+
const body=currentRows.map((r,i)=>[i+1,r.method,r.runtime,runtimeHost(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.composite_score_status,r.composite_rate_coverage,r.composite_timing_coverage,r.composite_timing_denominator,r.composite_metric_basis,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 eligible rows in selected language/scope/row-mode before search and visibility filters; provisional C++ scores use current admitted timing subsets','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]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.source_runtime]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.binary_sha256]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.eligible_column_set_sha256]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.measurement_status]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.timing_profile_status]))),r.timing_column_count,r.timing_aggregation,r.compression_time_timed_subset,r.decompression_time_timed_subset,r.timing_subset_coverage,r.timing_subset_denominator,r.timing_subset_status,JSON.stringify(r.timing_subset_source_profiles),JSON.stringify(r.timing_subset_hosts),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.source_family??s.family]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.source_comparison_profile??s.runtime]))),JSON.stringify(Object.fromEntries(r.source.map(s=>[s.dataset,s.source_execution_host??'source snapshot']))),metricAvailability(r,'compression_time').code,metricAvailability(r,'composite_score').code,FINAL160_INPUT_STATUS.scope_id,'not_quarantined_by_current_input_audit',JSON.stringify(FINAL160_INPUT_STATUS.pending_datasets.map(item=>item.dataset_id))].map(quote).join(','));
|
| 225 |
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);
|
| 226 |
}
|
| 227 |
function safeHttpUrl(value) {
|
availability.js
CHANGED
|
@@ -55,6 +55,11 @@ export function metricAvailability(row, key) {
|
|
| 55 |
}
|
| 56 |
if (['compression_time', 'decompression_time'].includes(key)) return timingAvailability(row);
|
| 57 |
if (['normalized_compression_time', 'normalized_decompression_time', 'composite_score'].includes(key)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
const timing = timingAvailability(row);
|
| 59 |
if (timing.code !== 'available') return timing;
|
| 60 |
if (Number(row?.workload_signature_count) > 1) return {
|
|
@@ -112,7 +117,7 @@ export function visibleColumns(columns, rows, profile, showUnavailable, touched
|
|
| 112 |
|
| 113 |
export function profileScopeText({profile, measuredDatasets, catalogDatasets}) {
|
| 114 |
const prefix = `${profileLabel(profile)} Β· ${measuredDatasets} measured datasets in this profile / ${catalogDatasets} catalog datasets.`;
|
| 115 |
-
if (profile === DEFAULT_PROFILE) return `${prefix} Duplicate C++ dataset/method pairs use the latest receipt-bound authority. Source profile and host remain visible in details and CSV. Strict timing
|
| 116 |
return `${prefix} These imported published results retain their original evidence boundaries; unqualified timing is not promoted into rankings.`;
|
| 117 |
}
|
| 118 |
|
|
|
|
| 55 |
}
|
| 56 |
if (['compression_time', 'decompression_time'].includes(key)) return timingAvailability(row);
|
| 57 |
if (['normalized_compression_time', 'normalized_decompression_time', 'composite_score'].includes(key)) {
|
| 58 |
+
if (row?.composite_score_status === 'provisional_unavailable') return {
|
| 59 |
+
code: 'provisional_missing_positive_weight_metric',
|
| 60 |
+
short: 'Missing weighted metric',
|
| 61 |
+
detail: 'A metric with positive score weight has no admitted current value. Missing values are not replaced with zero and the remaining weights are not renormalized.',
|
| 62 |
+
};
|
| 63 |
const timing = timingAvailability(row);
|
| 64 |
if (timing.code !== 'available') return timing;
|
| 65 |
if (Number(row?.workload_signature_count) > 1) return {
|
|
|
|
| 117 |
|
| 118 |
export function profileScopeText({profile, measuredDatasets, catalogDatasets}) {
|
| 119 |
const prefix = `${profileLabel(profile)} Β· ${measuredDatasets} measured datasets in this profile / ${catalogDatasets} catalog datasets.`;
|
| 120 |
+
if (profile === DEFAULT_PROFILE) return `${prefix} Duplicate C++ dataset/method pairs use the latest receipt-bound authority. Source profile and host remain visible in details and CSV. Strict timing still requires complete same-contract coverage. The provisional Composite score uses each method's current admitted timing subset and displays its timing coverage; missing values are never filled with zero.`;
|
| 121 |
return `${prefix} These imported published results retain their original evidence boundaries; unqualified timing is not promoted into rankings.`;
|
| 122 |
}
|
| 123 |
|
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=20261013-cpp-latest-v1">
|
| 10 |
-
<script src="app.js?v=20261016-
|
| 11 |
</head>
|
| 12 |
<body>
|
| 13 |
<a class="skip-link" href="#content">Skip to results</a>
|
|
@@ -69,7 +69,7 @@
|
|
| 69 |
<p id="availability-summary" class="availability-summary" aria-live="polite"></p>
|
| 70 |
<div id="score-controls" class="score-controls">
|
| 71 |
<label>Score weights Β· a: rate / b: compress / c: decompress<select id="weights" aria-label="Score weights a b c"></select></label>
|
| 72 |
-
<p id="score-note" class="muted" aria-live="polite">Non-negative weights in steps of 0.1, summing to 1.0.</p>
|
| 73 |
</div>
|
| 74 |
<div class="table-settings">
|
| 75 |
<label><input id="complete-only" type="checkbox"> Only methods covering the full selection</label>
|
|
@@ -120,9 +120,9 @@
|
|
| 120 |
<div><dt>Average compression rate β</dt><dd>Arithmetic mean of the per-dataset compression rates in the selected scope.</dd></div>
|
| 121 |
<div><dt>Overall compression rate β</dt><dd>Total compressed bytes divided by total original bytes over the selected measured records.</dd></div>
|
| 122 |
<div><dt>Compression / decompression cost β</dt><dd>For each result with admitted 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. Strict timing requires every current rate dataset for a method to have eligible timing. Missing and diagnostic-only timings remain unavailable.</dd></div>
|
| 123 |
-
<div><dt>Timed-subset compression / decompression cost β</dt><dd>Uses only current winning rows with admitted timing, and only when those rows share one exact source profile, host, timing contract, and aggregation basis. Each value displays N / M: timed datasets divided by current rate datasets. It
|
| 124 |
<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>
|
| 125 |
-
<div><dt>Composite score β</dt><dd>a Γ average compression rate + b Γ normalized average compression time + c Γ normalized average decompression time.
|
| 126 |
<div><dt>Average Rank β</dt><dd>Compute the same weighted score only among methods with the same dataset and eligible aggregate-id support hash, normalizing times inside that matched cohort. Rank lower scores first; ties share their average position. Then take the arithmetic mean of the method's available matched-cohort ranks. Weights are non-negative tenths summing to 1.0. Missing, N/A, failed, and unlike-support measurements do not receive ranks.</dd></div>
|
| 127 |
</dl>
|
| 128 |
<h3>Reading the rankings</h3>
|
|
|
|
| 7 |
<meta name="color-scheme" content="light dark">
|
| 8 |
<title>THULab | Time Series Compression Benchmark</title>
|
| 9 |
<link rel="stylesheet" href="style.css?v=20261013-cpp-latest-v1">
|
| 10 |
+
<script src="app.js?v=20261016-provisional-composite-v1" type="module"></script>
|
| 11 |
</head>
|
| 12 |
<body>
|
| 13 |
<a class="skip-link" href="#content">Skip to results</a>
|
|
|
|
| 69 |
<p id="availability-summary" class="availability-summary" aria-live="polite"></p>
|
| 70 |
<div id="score-controls" class="score-controls">
|
| 71 |
<label>Score weights Β· a: rate / b: compress / c: decompress<select id="weights" aria-label="Score weights a b c"></select></label>
|
| 72 |
+
<p id="score-note" class="muted" aria-live="polite">Non-negative weights in steps of 0.1, summing to 1.0. Current C++ scores are marked provisional until every method has complete admitted timing.</p>
|
| 73 |
</div>
|
| 74 |
<div class="table-settings">
|
| 75 |
<label><input id="complete-only" type="checkbox"> Only methods covering the full selection</label>
|
|
|
|
| 120 |
<div><dt>Average compression rate β</dt><dd>Arithmetic mean of the per-dataset compression rates in the selected scope.</dd></div>
|
| 121 |
<div><dt>Overall compression rate β</dt><dd>Total compressed bytes divided by total original bytes over the selected measured records.</dd></div>
|
| 122 |
<div><dt>Compression / decompression cost β</dt><dd>For each result with admitted 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. Strict timing requires every current rate dataset for a method to have eligible timing. Missing and diagnostic-only timings remain unavailable.</dd></div>
|
| 123 |
+
<div><dt>Timed-subset compression / decompression cost β</dt><dd>Uses only current winning rows with admitted timing, and only when those rows share one exact source profile, host, timing contract, and aggregation basis. Each value displays N / M: timed datasets divided by current rate datasets. It remains separate from strict timing and is used only by the explicitly labeled provisional C++ Composite score.</dd></div>
|
| 124 |
<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>
|
| 125 |
+
<div><dt>Composite score β</dt><dd>a Γ average compression rate + b Γ normalized average compression time + c Γ normalized average decompression time. The provisional C++ score uses all current rate datasets and each method's currently admitted timing subset; the score displays that timing coverage (for example, 134 / 135). Values are min-max normalized across rows eligible for every positively weighted metric. A zero-weight metric is not required, fixed weights are never renormalized, and missing values are never replaced with zero. Other profiles keep the strict complete-support rule. The provisional score will be refreshed when the remaining LZG timing result is admitted.</dd></div>
|
| 126 |
<div><dt>Average Rank β</dt><dd>Compute the same weighted score only among methods with the same dataset and eligible aggregate-id support hash, normalizing times inside that matched cohort. Rank lower scores first; ties share their average position. Then take the arithmetic mean of the method's available matched-cohort ranks. Weights are non-negative tenths summing to 1.0. Missing, N/A, failed, and unlike-support measurements do not receive ranks.</dd></div>
|
| 127 |
</dl>
|
| 128 |
<h3>Reading the rankings</h3>
|
ranking.js
CHANGED
|
@@ -29,13 +29,45 @@ function score(row,weights,encodeRange,decodeRange) {
|
|
| 29 |
return {normalized_compression_time:encode,normalized_decompression_time:decode,composite_score:valid(row)&&encode!==null&&decode!==null?weights[0]*row.compression_rate+weights[1]*encode+weights[2]*decode:null};
|
| 30 |
}
|
| 31 |
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
if(weights.length!==3||weights.some(w=>!finite(w)||w<0)||Math.abs(weights.reduce((s,w)=>s+w,0)-1)>1e-12)throw new Error('Invalid scoring weights.');
|
| 34 |
-
const
|
|
|
|
| 35 |
const workloadSignature=row=>row.source.map(r=>`${r.dataset}:${r.eligible_column_set_sha256??'legacy_snapshot_unbound'}`).sort().join('|');
|
| 36 |
-
const workloadSignatures=new Set(
|
| 37 |
const globallyComparable=workloadSignatures.size<=1;
|
| 38 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
const byDataset=new Map(),ranks=new Map(),details=new Map();
|
| 40 |
for(const row of rows) {
|
| 41 |
ranks.set(row.method,[]);
|
|
@@ -59,5 +91,18 @@ export function addRankingMetrics(rows,weights) {
|
|
| 59 |
start=end;
|
| 60 |
}
|
| 61 |
}
|
| 62 |
-
return rows.map(row=>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
}
|
|
|
|
| 29 |
return {normalized_compression_time:encode,normalized_decompression_time:decode,composite_score:valid(row)&&encode!==null&&decode!==null?weights[0]*row.compression_rate+weights[1]*encode+weights[2]*decode:null};
|
| 30 |
}
|
| 31 |
|
| 32 |
+
function provisionalCompositeInputs(row) {
|
| 33 |
+
return {
|
| 34 |
+
compression_rate:row.compression_rate,
|
| 35 |
+
compression_time:finite(row.compression_time)?row.compression_time:row.compression_time_timed_subset,
|
| 36 |
+
decompression_time:finite(row.decompression_time)?row.decompression_time:row.decompression_time_timed_subset,
|
| 37 |
+
};
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
function provisionalEligible(row,weights) {
|
| 41 |
+
const input=provisionalCompositeInputs(row);
|
| 42 |
+
return (weights[0]===0||(finite(input.compression_rate)&&input.compression_rate>0)) &&
|
| 43 |
+
(weights[1]===0||(finite(input.compression_time)&&input.compression_time>=0)) &&
|
| 44 |
+
(weights[2]===0||(finite(input.decompression_time)&&input.decompression_time>=0));
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
function provisionalScore(row,weights,encodeRange,decodeRange) {
|
| 48 |
+
const input=provisionalCompositeInputs(row);
|
| 49 |
+
const encode=weights[1]===0?null:minMax(input.compression_time,encodeRange);
|
| 50 |
+
const decode=weights[2]===0?null:minMax(input.decompression_time,decodeRange);
|
| 51 |
+
if(!provisionalEligible(row,weights)||(weights[1]>0&&encode===null)||(weights[2]>0&&decode===null))return {normalized_compression_time:encode,normalized_decompression_time:decode,composite_score:null};
|
| 52 |
+
return {
|
| 53 |
+
normalized_compression_time:encode,
|
| 54 |
+
normalized_decompression_time:decode,
|
| 55 |
+
composite_score:weights[0]*(finite(input.compression_rate)?input.compression_rate:0)+weights[1]*(encode??0)+weights[2]*(decode??0),
|
| 56 |
+
};
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
export function addRankingMetrics(rows,weights,options={}) {
|
| 60 |
if(weights.length!==3||weights.some(w=>!finite(w)||w<0)||Math.abs(weights.reduce((s,w)=>s+w,0)-1)>1e-12)throw new Error('Invalid scoring weights.');
|
| 61 |
+
const provisionalCurrentTiming=options.provisionalCurrentTiming===true;
|
| 62 |
+
const strictCandidates=rows.filter(r=>valid(r)&&r.source.every(valid));
|
| 63 |
const workloadSignature=row=>row.source.map(r=>`${r.dataset}:${r.eligible_column_set_sha256??'legacy_snapshot_unbound'}`).sort().join('|');
|
| 64 |
+
const workloadSignatures=new Set(strictCandidates.map(workloadSignature));
|
| 65 |
const globallyComparable=workloadSignatures.size<=1;
|
| 66 |
+
const provisionalCandidates=provisionalCurrentTiming?rows.filter(row=>provisionalEligible(row,weights)):[];
|
| 67 |
+
const candidates=provisionalCurrentTiming?provisionalCandidates:strictCandidates;
|
| 68 |
+
const provisionalInputs=provisionalCandidates.map(row=>provisionalCompositeInputs(row));
|
| 69 |
+
const encodeRange=provisionalCurrentTiming?(weights[1]>0?bounds(provisionalInputs,'compression_time'):null):(globallyComparable?bounds(strictCandidates,'compression_time'):null);
|
| 70 |
+
const decodeRange=provisionalCurrentTiming?(weights[2]>0?bounds(provisionalInputs,'decompression_time'):null):(globallyComparable?bounds(strictCandidates,'decompression_time'):null);
|
| 71 |
const byDataset=new Map(),ranks=new Map(),details=new Map();
|
| 72 |
for(const row of rows) {
|
| 73 |
ranks.set(row.method,[]);
|
|
|
|
| 91 |
start=end;
|
| 92 |
}
|
| 93 |
}
|
| 94 |
+
return rows.map(row=>{
|
| 95 |
+
const eligible=candidates.includes(row)&&(provisionalCurrentTiming||globallyComparable);
|
| 96 |
+
const scored=eligible?(provisionalCurrentTiming?provisionalScore(row,weights,encodeRange,decodeRange):score(row,weights,encodeRange,decodeRange)):{normalized_compression_time:null,normalized_decompression_time:null,composite_score:null};
|
| 97 |
+
return {...row,...scored,
|
| 98 |
+
composite_score_status:provisionalCurrentTiming?(scored.composite_score===null?'provisional_unavailable':'provisional_current_admitted_timing'):(scored.composite_score===null?'strict_unavailable':'strict_exact_support'),
|
| 99 |
+
composite_rate_coverage:row.coverage,
|
| 100 |
+
composite_timing_coverage:row.timing_subset_coverage,
|
| 101 |
+
composite_timing_denominator:row.timing_subset_denominator,
|
| 102 |
+
composite_metric_basis:provisionalCurrentTiming?'all-current-rate-datasets plus current-admitted-timing-subset':'strict-complete-exact-support',
|
| 103 |
+
average_rank:average(ranks.get(row.method)),rank_coverage:ranks.get(row.method).length,
|
| 104 |
+
normalization_reference_rows:provisionalCurrentTiming?candidates.length:(globallyComparable?strictCandidates.length:0),workload_signature_count:workloadSignatures.size,
|
| 105 |
+
encode_min:encodeRange?.[0]??null,encode_max:encodeRange?.[1]??null,decode_min:decodeRange?.[0]??null,decode_max:decodeRange?.[1]??null,
|
| 106 |
+
source:row.source.map(r=>({...r,...details.get(`${row.method}\0${r.dataset}\0${r.eligible_column_set_sha256??'legacy_snapshot_unbound'}`)}))};
|
| 107 |
+
});
|
| 108 |
}
|