jzxiao commited on
Commit
b8ee4bb
Β·
verified Β·
1 Parent(s): 9dacc7b

Show provisional Composite scores from current admitted results

Browse files

Use 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.

Files changed (4) hide show
  1. app.js +12 -9
  2. availability.js +6 -1
  3. index.html +4 -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=20261011-support-matched-v1';
3
- import {DEFAULT_PROFILE,profileLabel,defaultColumnVisible,metricAvailability,summarizeAvailability,visibleColumns,profileScopeText,aggregateTimedSubset,strictTimingMode} from './availability.js?v=20261013-overall-availability-v3';
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
- 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>`:''}`;
 
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 scoreStatus=!currentRows.length?'No candidate rows are visible; comparability is not inferred.':scoreAvailability.counts.composite_score===currentRows.length?'Composite scores use one complete exact dataset/support signature.':`Composite scores are withheld: ${scoreAvailability.reasons.length?scoreAvailability.reasons.join('; '):'a complete eligible normalization cohort is unavailable'}.`;
158
- $('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} Average Rank is computed only among rows with the same dataset and eligible aggregate-id support hash; ties share their average position. Missing, N/A, failed, and unlike-support results receive no rank.`;
 
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
- 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))}. Timed-subset values are shown only when every included timing row has one exact source profile, host, and timing contract; they never enter strict composite scores. 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>`;
 
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 measured rows in selected language/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]))),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(','));
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 and scores require complete same-contract coverage; partial admitted timing is labeled as a timed subset.`;
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-remaining6-completed5-incremental-v3" type="module"></script>
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 is descriptive and never enters strict composite scores.</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. A composite is published only when the displayed methods share one exact dataset and eligible aggregate-id support signature. If all times are equal, their normalized value is zero. All measured inputs must have usable timing metrics.</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>
 
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
- export function addRankingMetrics(rows,weights) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 candidates=rows.filter(r=>valid(r)&&r.source.every(valid));
 
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(candidates.map(workloadSignature));
37
  const globallyComparable=workloadSignatures.size<=1;
38
- const encodeRange=globallyComparable?bounds(candidates,'compression_time'):null,decodeRange=globallyComparable?bounds(candidates,'decompression_time'):null;
 
 
 
 
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=>({...row,...(globallyComparable&&candidates.includes(row)?score(row,weights,encodeRange,decodeRange):{normalized_compression_time:null,normalized_decompression_time:null,composite_score:null}),average_rank:average(ranks.get(row.method)),rank_coverage:ranks.get(row.method).length,normalization_reference_rows:globallyComparable?candidates.length:0,workload_signature_count:workloadSignatures.size,encode_min:encodeRange?.[0]??null,encode_max:encodeRange?.[1]??null,decode_min:decodeRange?.[0]??null,decode_max:decodeRange?.[1]??null,source:row.source.map(r=>({...r,...details.get(`${row.method}\0${r.dataset}\0${r.eligible_column_set_sha256??'legacy_snapshot_unbound'}`)}))}));
 
 
 
 
 
 
 
 
 
 
 
 
 
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
  }