(name: string, matchesSlice: typeof matches, epochs: number)
| 80 | }); |
| 81 | |
| 82 | const runOneTournament = (name: string, matchesSlice: typeof matches, epochs: number) => { |
| 83 | const ratingsCache: Record<string, { mu: number; sigma: number; matches: number }> = {}; |
| 84 | |
| 85 | const getRating = (model: string) => ratingsCache[model] ?? { mu: 24, sigma: 1, matches: 0 }; |
| 86 | |
| 87 | const updateRating = (model1: string, model2: string, score: number) => { |
| 88 | const rating1 = getRating(model1); |
| 89 | const rating2 = getRating(model2); |
| 90 | |
| 91 | const [team1, team2] = rate([[rating1], [rating2]], { |
| 92 | score: [score, 1 - score], |
| 93 | model: bradleyTerryFull, |
| 94 | }); |
| 95 | |
| 96 | const newRating1 = team1?.[0]; |
| 97 | const newRating2 = team2?.[0]; |
| 98 | |
| 99 | if (!newRating1 || !newRating2) throw new Error("Expected new rating"); |
| 100 | |
| 101 | ratingsCache[model1] = { ...newRating1, matches: rating1.matches + 1 }; |
| 102 | ratingsCache[model2] = { ...newRating2, matches: rating2.matches + 1 }; |
| 103 | }; |
| 104 | |
| 105 | for (let i = 0; i < epochs; i++) { |
| 106 | for (const match of shuffle(matchesSlice)) { |
| 107 | if (match.score !== null) updateRating(match.model1, match.model2, match.score); |
| 108 | } |
| 109 | } |
| 110 | const ratings = Object.entries(ratingsCache) |
| 111 | .map(([model, r]) => ({ model, ...r, ordinal: ordinal(r) })) |
| 112 | .sort((a, b) => b.mu - a.mu); |
| 113 | |
| 114 | const ratingScale = 1200 / rating().mu; |
| 115 | |
| 116 | console.log(`${name} (${matchesSlice.length} matches, ${epochs} epochs)`); |
| 117 | console.log( |
| 118 | table([ |
| 119 | ["Model", "Mean", "Std Dev", "Ordinal", "Matches"], |
| 120 | ...ratings.map((r) => [ |
| 121 | r.model, |
| 122 | (r.mu * ratingScale).toFixed(0), |
| 123 | (r.sigma * ratingScale).toFixed(1), |
| 124 | (ordinal(r) * ratingScale).toFixed(0), |
| 125 | r.matches / epochs, |
| 126 | ]), |
| 127 | ]), |
| 128 | ); |
| 129 | }; |
| 130 | |
| 131 | runOneTournament("All", matches, 50); |
| 132 | runOneTournament("All (augmented)", augmentedMatches, 20); |
no test coverage detected