|
|
|
(define-module (deliberate borda)
|
|
|
|
#:use-module (srfi srfi-1)
|
|
|
|
#:use-module (deliberate preference)
|
|
|
|
#:use-module (deliberate utils)
|
|
|
|
#:export (borda-score social-choice-borda social-preference-borda)
|
|
|
|
#:export (profile->scores groups->totals profile-borda-totals))
|
|
|
|
|
|
|
|
;; Calculate the borda score of each alternative in `ranked`.
|
|
|
|
;;
|
|
|
|
;; Parameters:
|
|
|
|
;; alternatives: Complete list of alternatives.
|
|
|
|
;; ranked: List of alternatives ranked from most to least preferred.
|
|
|
|
;; This list need not include all possible alternatives. Any not included
|
|
|
|
;; will be treated as tied for last place.
|
|
|
|
;;
|
|
|
|
(define (borda-score alternatives ranked)
|
|
|
|
;; Check whether all alternatives have been scored
|
|
|
|
(if (nil? alternatives)
|
|
|
|
'()
|
|
|
|
;; Check whether all ranked alternatives have been scored
|
|
|
|
(if (nil? ranked)
|
|
|
|
;; Assign average remaining score to all unranked alternatives
|
|
|
|
(let* ((n (length alternatives))
|
|
|
|
(score (/ (- n 1) 2)))
|
|
|
|
(map cons alternatives (const-list n score)))
|
|
|
|
;; Just use next rank
|
|
|
|
(let* ((alt (car ranked))
|
|
|
|
(remaining (delete alt alternatives)))
|
|
|
|
(cons
|
|
|
|
;; Score of an alternative is the number of
|
|
|
|
;; lesser-ranked alternatives
|
|
|
|
(cons alt (length remaining))
|
|
|
|
(borda-score remaining (cdr ranked))))
|
|
|
|
)))
|
|
|
|
|
|
|
|
;; Produce a list of borda scores for multiple rankings.
|
|
|
|
;;
|
|
|
|
;; Parameters:
|
|
|
|
;; alternatives: List of alternatives.
|
|
|
|
;; counts: list of pairs of the form (`count` . `ranking`).
|
|
|
|
;;
|
|
|
|
;; Returns:
|
|
|
|
;; A list of cells of the form (`alternative` . `score`). Alternatives
|
|
|
|
;; may appear in multiple cells, one for each ranking.
|
|
|
|
;;
|
|
|
|
(define (counts->scores alternatives counts)
|
|
|
|
(apply append
|
|
|
|
(map (lambda (pair)
|
|
|
|
(borda-score alternatives (cdr pair)))
|
|
|
|
counts)))
|
|
|
|
|
|
|
|
;; Combine grouped borda scores into one total for each alternative.
|
|
|
|
;;
|
|
|
|
;; Parameters:
|
|
|
|
;; groups: A list of the form:
|
|
|
|
;; ((`alt-1` (`alt-1` . `alt-1-score-1`) (`alt-1` . `alt-1-score-2`) ...)
|
|
|
|
;; (`alt-2` (`alt-2` . `alt-2-score-1`) (`alt-2` . `alt-2-score-2`) ...)
|
|
|
|
;; ...)
|
|
|
|
;;
|
|
|
|
(define (groups->totals groups)
|
|
|
|
(map (lambda (elt)
|
|
|
|
(cons (car elt)
|
|
|
|
(reduce + 0 (map cdr (cdr elt)))))
|
|
|
|
groups))
|
|
|
|
|
|
|
|
;; Calculate total borda counts for each alternative in `counts`.
|
|
|
|
;;
|
|
|
|
;; Parameters:
|
|
|
|
;; alternatives: List of all alternatives
|
|
|
|
;; counts: List of cells of the form (`count` . `ranking`)
|
|
|
|
;;
|
|
|
|
;; Returns:
|
|
|
|
;; A list of the form ((`alt-1` . `total-1`) (`alt-2` . `total-2`) ...)
|
|
|
|
;;
|
|
|
|
(define (profile-borda-totals alternatives counts)
|
|
|
|
(let* ((scores (counts->scores alternatives counts))
|
|
|
|
(groups (group-by car scores))
|
|
|
|
(totals (groups->totals groups)))
|
|
|
|
totals))
|
|
|
|
|
|
|
|
;; Find the social prefrence ranking using the Borda count method.
|
|
|
|
;;
|
|
|
|
;; TODO - handle ties
|
|
|
|
;;
|
|
|
|
;; Parameters:
|
|
|
|
;; alternatives: List of all alternatives
|
|
|
|
;; counts: List of cells of the form (`count` . `ranking`)
|
|
|
|
;;
|
|
|
|
;; Returns:
|
|
|
|
;; A list of lists. The outer list represents the social ranking from
|
|
|
|
;; most to least preferred. The inner lists represent sets of alternatives
|
|
|
|
;; tied for the same place.
|
|
|
|
;;
|
|
|
|
(define (social-preference-borda alternatives counts)
|
|
|
|
(let ((totals (profile-borda-totals alternatives counts)))
|
|
|
|
;; We use > instead of < for to rank in decreasing score order
|
|
|
|
(map (compose list car)
|
|
|
|
(sort totals (lambda (x y) (> (cdr x) (cdr y)))))))
|
|
|
|
|
|
|
|
;; Find the winner of a vote using the Borda count method.
|
|
|
|
;;
|
|
|
|
;; Parameters:
|
|
|
|
;; alternatives: List of all alternatives
|
|
|
|
;; counts: List of cells of the form (`count` . `ranking`)
|
|
|
|
;;
|
|
|
|
;; Returns:
|
|
|
|
;; A list contianing alternatives tied for first place.
|
|
|
|
;;
|
|
|
|
(define (social-choice-borda alternatives counts)
|
|
|
|
(car (social-preference-borda alternatives counts)))
|