You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Remove unused select() method from PowerRanker (#115)
The select() method has been superseded by activeSelect(), which uses a more sophisticated multi-signal approach (coverage, proximity, position) instead of simple variance weighting.
Remove dead code: select(), getVariances(), getVariance(), SelectOptions, ImpactTransform.
Update README to document the actual bidirectional encoding and activeSelect() API.
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: backend/src/lib/power/README.md
+15-11Lines changed: 15 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,8 +7,8 @@ Ported from [zaratanDotWorld/choreWheel](https://github.com/zaratanDotWorld/chor
7
7
8
8
### Ranking
9
9
10
-
Pairwise preferences are accumulated into an N×N matrix where `matrix[i][j]` represents the strength of preference for item j over item i.
11
-
Preferences are scaled from the input range [0, 1] to [-1, 1] centered at 0.5 (no preference).
10
+
Pairwise preferences are accumulated into an N×N matrix using bidirectional encoding: a score `s` adds `s` to `matrix[source][target]` and `1-s` to `matrix[target][source]`.
11
+
This means every observation informs both items — a strong preference (s=1) flows entirely toward the winner, while an even vote (s=0.5) splits equally.
12
12
13
13
The diagonal holds each item's total received preference (column sum), making it a self-reinforcing signal.
14
14
The matrix is row-normalized into a stochastic matrix, then power iteration finds the dominant eigenvector — the stationary distribution that becomes the ranking.
`select()` chooses which pairs to present next using variance-weighted sampling without replacement.
21
-
Each pair's uncertainty is modeled as a Beta distribution: `Beta(matrix[i][j] + 1, matrix[j][i] + 1)`.
22
-
Higher variance means less certainty about the relative ranking — so those pairs are sampled more often.
20
+
`activeSelect()` chooses which pairs to present next using three composable signals:
23
21
24
-
With `impact: true`, the variance is multiplied by `weight_a * weight_b` (the eigenvector scores), prioritizing uncertain pairs between high-ranked items.
22
+
-**coverage** (`1/√(1+n_i) × 1/√(1+n_j)`) — dominates early when observations are sparse.
23
+
-**proximity** (`1/(1+|pos_i-pos_j|)`) — favors pairs that are close in rank.
24
+
-**position** (`1/√(pos_i×pos_j)`) — favors pairs near the top of the ranking.
25
+
26
+
A regularization parameter `r` (0–1) controls how strongly these signals influence selection via a power transform.
27
+
At `r=0`, selection is uniform; at `r=1` (default), the full weighting applies.
25
28
26
29
## API
27
30
@@ -40,19 +43,20 @@ ranker.addPreferences([
40
43
// Get rankings (Map<string, number>, values sum to 1)
41
44
const rankings =ranker.run();
42
45
43
-
// Get all pairs with their variance weights
44
-
const allPairs =ranker.select();
46
+
// Get all pairs with their selection weights
47
+
const allPairs =ranker.activeSelect();
45
48
46
49
// Select pairs for a judging session (weighted sampling without replacement)
47
-
const pairs =ranker.select({
50
+
const pairs =ranker.activeSelect({
48
51
num: 5,
49
52
exclude: newSet(['a:b']), // pairs already judged
50
-
impact: true, // weight by item importance
53
+
terms: ['coverage', 'proximity', 'position'], // default: all three
0 commit comments