(define-module (deliberate irv) #:use-module (ice-9 receive) #:use-module (srfi srfi-1) #:use-module (deliberate preference) #:use-module (deliberate utils) #:export (irv-counts->first-counts irv-first-counts->scores social-choice-irv social-preference-irv) #:export (delete-lowest irv-round lowest-count) ) ;; Extract first-place alternatives from preference counts (define (irv-counts->first-counts counts) (map (lambda (count-ranked) (cons (pref-count count-ranked) (car (pref-ranked count-ranked)))) counts)) (define (irv-first-counts->scores first-counts) (let ((groups (group-by cdr first-counts))) (map (lambda (group) (cons (reduce + 0 (map car (cdr group))) (car group))) groups))) (define (lowest-count scores) (apply min (map car scores))) (define (delete-lowest scores) (let ((lowest (lowest-count scores))) (receive (to-delete to-keep) (partition (lambda (elt) (= lowest (car elt))) scores) (cons (map cdr to-keep) (map cdr to-delete)) ))) (define (irv-round counts) (let* ((scores (irv-first-counts->scores (irv-counts->first-counts counts))) (keep-delete (delete-lowest scores)) (keep-alts (car keep-delete)) (delete-alts (cdr keep-delete))) (cons delete-alts (filter-empty (map (lambda (count-elt) (cons (car count-elt) (filter (lambda (alt) (memv alt keep-alts)) (cdr count-elt)) )) counts))) )) (define (filter-empty counts) (filter (lambda (count-elt) (not (nil? (cdr count-elt)))) counts)) ;; 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-irv counts) (reverse (social-preference-irv-rev counts))) (define (social-preference-irv-rev counts) (if (nil? counts) '() (let* ((delete-counts (irv-round counts)) (delete-alts (car delete-counts)) (next-counts (cdr delete-counts))) (cons delete-alts (social-preference-irv-rev next-counts)) ))) ;; 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-irv counts) (car (social-preference-irv counts)))