Schulze is a Go implementation of the Schulze method voting system. The system is developed in 1997 by Markus Schulze. It is a single winner preferential voting. The Schulze method is also known as Schwartz Sequential dropping (SSD), cloneproof Schwartz sequential dropping (CSSD), the beatpath method, beatpath winner, path voting, and path winner.
The Schulze method is a Condorcet method, which means that if there is a candidate who is preferred by a majority over every other candidate in pairwise comparisons, then this candidate will be the winner when the Schulze method is applied.
White paper Markus Schulze, "The Schulze Method of Voting".
Vote
and Compute
are the core functions in the library. They implement the Schulze method on the most compact required representation of votes, here called preferences that is properly initialized with the NewPreferences
function. Vote
writes the Ballot
values to the provided preferences and Compute
returns the ranked list of choices from the preferences, with the first one as the winner. In case that there are multiple choices with the same score, the returned tie
boolean flag is true.
The act of voting represents calling the Vote
function with a Ballot
map where keys in the map are choices and values are their rankings. Lowest number represents the highest rank. Not all choices have to be ranked and multiple choices can have the same rank. Ranks do not have to be in consecutive order.
Unvote
function allows to update the pairwise preferences in a way to cancel the previously added Ballot
to preferences using Vote
function. It is useful to change the vote without the need to re-vote all ballots.
SetChoices
allows to update the pairwise preferences if the choices has to be changed during voting. New choices can be added, existing choices can be removed or rearranged. New choices will have no preferences against existing choices, neither existing choices will have preferences against the new choices.
Voting
holds number of votes for every pair of choices. It is a convenient construct to use when the preferences slice does not have to be exposed, and should be kept safe from accidental mutation. Methods on the Voting type are not safe for concurrent calls.
package main
import (
"fmt"
"log"
"resenje.org/schulze"
)
func main() {
choices := []string{"A", "B", "C"}
preferences := schulze.NewPreferences(len(choices))
// First vote.
if err := schulze.Vote(preferences, choices, schulze.Ballot[string]{
"A": 1,
}); err != nil {
log.Fatal(err)
}
// Second vote.
if err := schulze.Vote(preferences, choices, schulze.Ballot[string]{
"A": 1,
"B": 1,
"C": 2,
}); err != nil {
log.Fatal(err)
}
// Calculate the result.
result, tie := schulze.Compute(preferences, choices)
if tie {
log.Fatal("tie")
}
fmt.Println("winner:", result[0].Choice)
}
This application is distributed under the BSD-style license found in the LICENSE file.