Skip to content

Commit

Permalink
Add Strength and Advantage to the Result
Browse files Browse the repository at this point in the history
  • Loading branch information
janos committed Jan 20, 2024
1 parent e63d825 commit 5dd5056
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 50 deletions.
42 changes: 34 additions & 8 deletions schulze.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ type Result[C comparable] struct {
Index int
// Number of wins in pairwise comparisons to other choices votings.
Wins int
// Total number of votes in wins in pairwise comparisons to other choices
// votings.
// Strength does not effect the winner, and may be less then the
// Strength of the choice with more wins.
Strength int
// Total number of preferred votes (difference between votes of the winner
// choice and the opponent choice) in wins in pairwise comparisons to other
// choices votings. Advantage does not effect the winner, and may be less
// then the Advantage of the choice with more wins. The code with less wins
// and greater Advantage had stronger but fewer wins and that information
// can be taken into the analysis of the results.
Advantage int
}

// Compute calculates a sorted list of choices with the total number of wins for
Expand Down Expand Up @@ -324,24 +336,38 @@ func calculateResults[C comparable](choices []C, strengths []int) (results []Res
results = make([]Result[C], 0, choicesCount)

for i := 0; i < choicesCount; i++ {
var count int
var wins int
var popularity int
var advantage int

for j := 0; j < choicesCount; j++ {
if i != j {
if strengths[i*choicesCount+j] > strengths[j*choicesCount+i] {
count++
sij := strengths[i*choicesCount+j]
sji := strengths[j*choicesCount+i]
if sij > sji {
wins++
popularity += sij
advantage += sij - sji
}
}
}
results = append(results, Result[C]{Choice: choices[i], Index: i, Wins: count})

results = append(results, Result[C]{
Choice: choices[i],
Index: i,
Wins: wins,
Strength: popularity,
Advantage: advantage,
})
}

sort.Slice(results, func(i, j int) bool {
if results[i].Wins == results[j].Wins {
return results[i].Index < results[j].Index
if results[i].Wins != results[j].Wins {
return results[i].Wins > results[j].Wins
}
if results[i].Strength != results[j].Strength {
return results[i].Strength > results[j].Strength
}
return results[i].Wins > results[j].Wins
return results[i].Index < results[j].Index
})

if len(results) >= 2 {
Expand Down
84 changes: 42 additions & 42 deletions schulze_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestVoting(t *testing.T) {
name: "single option no votes",
choices: []string{"A"},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 0},
{Choice: "A", Index: 0, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -48,7 +48,7 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"A": 1}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 0},
{Choice: "A", Index: 0, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -58,8 +58,8 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"A": 1}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 1},
{Choice: "B", Index: 1, Wins: 0},
{Choice: "A", Index: 0, Wins: 1, Strength: 1, Advantage: 1},
{Choice: "B", Index: 1, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -70,8 +70,8 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"A": 1, "B": 2}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 1},
{Choice: "B", Index: 1, Wins: 0},
{Choice: "A", Index: 0, Wins: 1, Strength: 2, Advantage: 2},
{Choice: "B", Index: 1, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -83,9 +83,9 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"A": 1, "B": 2, "C": 3}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 2},
{Choice: "B", Index: 1, Wins: 1},
{Choice: "C", Index: 2, Wins: 0},
{Choice: "A", Index: 0, Wins: 2, Strength: 6, Advantage: 6},
{Choice: "B", Index: 1, Wins: 1, Strength: 2, Advantage: 2},
{Choice: "C", Index: 2, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -96,9 +96,9 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"B": 1}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 1},
{Choice: "B", Index: 1, Wins: 1},
{Choice: "C", Index: 2, Wins: 0},
{Choice: "A", Index: 0, Wins: 1, Strength: 1, Advantage: 1},
{Choice: "B", Index: 1, Wins: 1, Strength: 1, Advantage: 1},
{Choice: "C", Index: 2, Wins: 0, Strength: 0, Advantage: 0},
},
tie: true,
},
Expand All @@ -112,11 +112,11 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"A": 1, "B": 200, "C": 10}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 4},
{Choice: "B", Index: 1, Wins: 2},
{Choice: "C", Index: 2, Wins: 2},
{Choice: "D", Index: 3, Wins: 0},
{Choice: "E", Index: 4, Wins: 0},
{Choice: "A", Index: 0, Wins: 4, Strength: 13, Advantage: 13},
{Choice: "B", Index: 1, Wins: 2, Strength: 8, Advantage: 8},
{Choice: "C", Index: 2, Wins: 2, Strength: 6, Advantage: 6},
{Choice: "D", Index: 3, Wins: 0, Strength: 0, Advantage: 0},
{Choice: "E", Index: 4, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -129,11 +129,11 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"A": 1, "B": 200, "C": 10}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 4},
{Choice: "B", Index: 1, Wins: 2},
{Choice: "C", Index: 2, Wins: 2},
{Choice: "C", Index: 3, Wins: 0},
{Choice: "C", Index: 4, Wins: 0},
{Choice: "A", Index: 0, Wins: 4, Strength: 13, Advantage: 13},
{Choice: "B", Index: 1, Wins: 2, Strength: 8, Advantage: 8},
{Choice: "C", Index: 2, Wins: 2, Strength: 6, Advantage: 6},
{Choice: "C", Index: 3, Wins: 0, Strength: 0, Advantage: 0},
{Choice: "C", Index: 4, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand Down Expand Up @@ -194,11 +194,11 @@ func TestVoting(t *testing.T) {
{vote: schulze.Ballot[string]{"E": 1, "B": 2, "A": 3, "D": 4, "C": 5}},
},
result: []schulze.Result[string]{
{Choice: "E", Index: 4, Wins: 4},
{Choice: "A", Index: 0, Wins: 3},
{Choice: "C", Index: 2, Wins: 2},
{Choice: "B", Index: 1, Wins: 1},
{Choice: "D", Index: 3, Wins: 0},
{Choice: "E", Index: 4, Wins: 4, Strength: 112, Advantage: 16},
{Choice: "A", Index: 0, Wins: 3, Strength: 86, Advantage: 11},
{Choice: "C", Index: 2, Wins: 2, Strength: 58, Advantage: 2},
{Choice: "B", Index: 1, Wins: 1, Strength: 33, Advantage: 5},
{Choice: "D", Index: 3, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -209,7 +209,7 @@ func TestVoting(t *testing.T) {
{unvote: schulze.Record[string]{{"A"}}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 0},
{Choice: "A", Index: 0, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -220,8 +220,8 @@ func TestVoting(t *testing.T) {
{unvote: schulze.Record[string]{{"A"}, {"B"}}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 0},
{Choice: "B", Index: 1, Wins: 0},
{Choice: "A", Index: 0, Wins: 0, Strength: 0, Advantage: 0},
{Choice: "B", Index: 1, Wins: 0, Strength: 0, Advantage: 0},
},
tie: true,
},
Expand All @@ -233,8 +233,8 @@ func TestVoting(t *testing.T) {
{unvote: schulze.Record[string]{}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 1},
{Choice: "B", Index: 1, Wins: 0},
{Choice: "A", Index: 0, Wins: 1, Strength: 1, Advantage: 1},
{Choice: "B", Index: 1, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -248,11 +248,11 @@ func TestVoting(t *testing.T) {
{unvote: schulze.Record[string]{{"A"}, {"B", "C"}, {"D", "E"}}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 3},
{Choice: "B", Index: 1, Wins: 2},
{Choice: "C", Index: 2, Wins: 2},
{Choice: "D", Index: 3, Wins: 0},
{Choice: "E", Index: 4, Wins: 0},
{Choice: "A", Index: 0, Wins: 3, Strength: 8, Advantage: 8},
{Choice: "B", Index: 1, Wins: 2, Strength: 6, Advantage: 6},
{Choice: "C", Index: 2, Wins: 2, Strength: 4, Advantage: 4},
{Choice: "D", Index: 3, Wins: 0, Strength: 0, Advantage: 0},
{Choice: "E", Index: 4, Wins: 0, Strength: 0, Advantage: 0},
},
},
{
Expand All @@ -268,11 +268,11 @@ func TestVoting(t *testing.T) {
{unvote: schulze.Record[string]{{"B", "C"}, {"A"}, {"D", "E"}}},
},
result: []schulze.Result[string]{
{Choice: "A", Index: 0, Wins: 4},
{Choice: "C", Index: 2, Wins: 3},
{Choice: "B", Index: 1, Wins: 2},
{Choice: "D", Index: 3, Wins: 0},
{Choice: "E", Index: 4, Wins: 0},
{Choice: "A", Index: 0, Wins: 4, Strength: 4, Advantage: 4},
{Choice: "C", Index: 2, Wins: 3, Strength: 3, Advantage: 3},
{Choice: "B", Index: 1, Wins: 2, Strength: 2, Advantage: 2},
{Choice: "D", Index: 3, Wins: 0, Strength: 0, Advantage: 0},
{Choice: "E", Index: 4, Wins: 0, Strength: 0, Advantage: 0},
},
},
} {
Expand Down

0 comments on commit 5dd5056

Please sign in to comment.