Sam-Izdat / govote

voting system implementations for polling and prefential voting in golang
MIT License
26 stars 6 forks source link

Partial ballots #6

Open loopfz opened 3 years ago

loopfz commented 3 years ago

Testing schulze / instant-runoff, I notice that when using partial ballots the values not present in any ballot are heavily favored as winners.

I think this fixes the behavior for instant-runoff:

 func (p *InstantRunoffPoll) runRound(elim map[string]bool) map[string]int {
    tally := make(map[string]int)                // scores keyed by candidate name
+   for _, c := range p.candidates {
+        if !elim[c] {
+            tally[c] = 0
+        }
+   }

I haven't looked into schulze yet.

What do you think?

Sam-Izdat commented 3 years ago

I'll take a look when I have a moment, thanks. Any chance you could post an example of expected vs erroneous results?

loopfz commented 3 years ago

Sure:

func main() {
    candidates := []string{"a", "b", "c", "d"}

    poll, _ := govote.Schulze.New(candidates)

    poll.AddBallot([]string{"a", "b"})
    poll.AddBallot([]string{"a", "c"})
    poll.AddBallot([]string{"c"})
    fmt.Println(poll.Evaluate())
}

Results in:

[a d] [{a 3} {d 3} {b 2} {c 2}] <nil>
loopfz commented 3 years ago

And with instant runoff

func main() {
    candidates := []string{"a", "b", "c", "d"}

    poll, _ := govote.InstantRunoff.New(candidates)

    poll.AddBallot([]string{"a", "b"})
    poll.AddBallot([]string{"a", "c"})
    poll.AddBallot([]string{"c"})
    fmt.Println(poll.Evaluate())
}

Result =

[a b d] [[{a 2} {c 1}] [{a 2}]] <nil>
loopfz commented 3 years ago

Have you had a chance to look into it ?