~edwargix/tallyard

eb2145e58e2ad1e1dbefa0f44e30f955ee97c03e — David Florness 4 years ago 14ebc85
Schulze method
1 files changed, 63 insertions(+), 0 deletions(-)

M election/voter.go
M election/voter.go => election/voter.go +63 -0
@@ 7,6 7,7 @@ import (
	"fmt"
	"io"
	"math/big"
	"sort"
	"sync"
	"time"



@@ 290,4 291,66 @@ func printResults(result []byte, candidates []Candidate) {
			}
		}
	}

	// Schulze method computation
	// https://en.wikipedia.org/wiki/Schulze_method#Implementation
	min := func(x, y int) int {
		if x < y {
			return x
		}
		return y
	}
	max := func(x, y int) int {
		if x > y {
			return x
		}
		return y
	}
	p := make(map[int]map[int]int)
	for i := range candidates {
		for j := range candidates {
			if i != j {
				if p[i] == nil {
					p[i] = make(map[int]int)
				}
				if result[i*n+j] > result[j*n+i] {
					p[i][j] = int(result[i*n+j])
				} else {
					p[i][j] = 0
				}
			}
		}
	}
	for i := range candidates {
		for j := range candidates {
			if i != j {
				for k := range candidates {
					if i != k && j != k {
						p[j][k] = max(p[j][k], min(p[j][i], p[i][k]))
					}
				}
			}
		}
	}
	order := []int{}
	for i := range candidates {
		k := sort.Search(len(order), func(j int) bool {
			return p[i][order[j]] > p[order[j]][i]
		})
		newOrder := make([]int, len(order)+1)
		copy(newOrder[:k], order[:k])
		newOrder[k] = i
		copy(newOrder[k+1:], order[k:])
		order = newOrder
	}
	fmt.Printf("\n=== Schulze Method Ranking ===\n")
	for i:= 0; i < len(order); i++ {
		rank := i+1 // don't want 0th place
		fmt.Printf("%d) %s\n", rank, candidates[order[i]])
		// candidates that are tied get the same rank
		for i+1 < len(order) && p[order[i]][order[i+1]] == p[order[i+1]][order[i]] {
			fmt.Printf("%d) %s\n", rank, candidates[order[i+1]])
			i++
		}
	}
}