| 652 | } |
| 653 | |
| 654 | function bucketedTiers( |
| 655 | rows: Array<EvalRow>, |
| 656 | getter: (row: EvalRow) => number | undefined, |
| 657 | setter: (row: EvalRow, tier: number) => void, |
| 658 | lowerIsBetter: boolean, |
| 659 | ) { |
| 660 | for (const category of ['local', 'cloud'] as const) { |
| 661 | const bucket = rows.filter((r) => r.modelCategory === category) |
| 662 | const values = bucket |
| 663 | .map((r) => ({ row: r, value: getter(r) })) |
| 664 | .filter( |
| 665 | (r): r is { row: EvalRow; value: number } => |
| 666 | typeof r.value === 'number', |
| 667 | ) |
| 668 | |
| 669 | if (values.length === 0) continue |
| 670 | const min = Math.min(...values.map((v) => v.value)) |
| 671 | const max = Math.max(...values.map((v) => v.value)) |
| 672 | |
| 673 | for (const entry of values) { |
| 674 | if (max === min) { |
| 675 | setter(entry.row, 5) |
| 676 | continue |
| 677 | } |
| 678 | const normalized = lowerIsBetter |
| 679 | ? (max - entry.value) / (max - min) |
| 680 | : (entry.value - min) / (max - min) |
| 681 | const tier = Math.round(1 + normalized * 4) |
| 682 | setter(entry.row, Math.max(1, Math.min(5, tier))) |
| 683 | } |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | function printTable(rows: Array<EvalRow>) { |
| 688 | console.log('\n=== Results ===\n') |