SampleVoteYakHandler: ranked-pairs.scm

File ranked-pairs.scm, 4.8 KB (added by alexshinn, 2 years ago)

portable ranked-pairs implementation

Line 
1
2(define (remove pred ls)
3  (let lp ((ls ls) (res '()))
4    (cond ((null? ls) (reverse res))
5          ((pred (car ls)) (lp (cdr ls) (cons (car ls) res)))
6          (else (lp (cdr ls) res)))))
7
8(define (union/eq a b)
9  (cond ((null? a) b)
10        ((memq (car a) b) (union/eq (cdr a) b))
11        (else (union/eq (cdr a) (cons (car a) b)))))
12
13(define (join-candidates ranked res)
14  (let lp ((ls ranked) (res res))
15    (cond ((null? ls) res)
16          ((symbol? (car ls)) (lp (cdr ls) (union/eq (list (car ls)) res)))
17          (else (lp (cdr ls) (union/eq (car ls) res))))))
18
19(define (extract-candidates votes)
20  (let lp ((ls votes) (res '()))
21    (if (null? ls)
22        res
23        (lp (cdr ls) (join-candidates (cdar ls) res)))))
24
25(define (vote-preferred? a b ls)
26  (and (pair? ls)
27       (let ((tmp (if (symbol? (car ls)) (list (car ls)) (car ls))))
28         (cond ((memq a tmp) (not (memq b tmp)))
29               ((memq b tmp) #f)
30               (else (vote-preferred? a b (cdr ls)))))))
31
32(define (tally-vote a b votes)
33  (let lp ((ls votes) (res 0))
34    (if (null? ls)
35        res
36        (lp (cdr ls) (if (vote-preferred? a b (cdar ls)) (+ res 1) res)))))
37
38(define (tally-votes votes)
39  (let ((candidates (extract-candidates votes)))
40    (let lp1 ((ls1 candidates) (res '()))
41      (if (null? ls1)
42          res
43          (let lp2 ((ls2 candidates) (res res))
44            (cond
45             ((null? ls2)
46              (lp1 (cdr ls1) res))
47             ((eq? (car ls1) (car ls2))
48              (lp2 (cdr ls2) res))
49             (else
50              (lp2 (cdr ls2)
51                   (cons (cons (cons (car ls1) (car ls2))
52                               (tally-vote (car ls1) (car ls2) votes))
53                         res)))))))))
54
55(define (pair-score pair pairs)
56  (cond ((assoc pair pairs) => cdr) (else 0)))
57
58(define (sort-pairs pairs)
59  ;; requires SRFI-98 compatible `sort': (sort ls less?)
60  (sort pairs
61        (lambda (a b)
62          (or (> (cdr a) (cdr b))
63              (and (= (cdr a) (cdr b))
64                   (let ((a^-1 (pair-score (cons (cdar a) (caar a)) pairs))
65                         (b^-1 (pair-score (cons (cdar b) (caar b)) pairs)))
66                     (< a^-1 b^-1)))))))
67
68(define (insert-edge a b graph)
69  (let lp ((ls graph) (rev '()))
70    (cond
71     ((null? ls)
72      (cons (list a b) graph))
73     ((equal? a (caar ls))
74      (if (member b (cdar ls))
75          graph
76          (append (reverse rev)
77                  (cons (cons (caar ls) (cons b (cdar ls))) (cdr ls)))))
78     (else
79      (lp (cdr ls) (cons (car ls) rev))))))
80
81(define (graph-ref graph a)
82  (cond ((assoc a graph) => cdr) (else '())))
83
84;; can a be reached from b with the given graph?
85(define (graph-reachable? a b graph)
86  (let lp ((ls (graph-ref graph b))
87           (seen '()))
88    (cond
89     ((null? ls) #f)
90     ((equal? a (car ls)) #t)
91     (else
92      (lp (append (remove (lambda (x) (member x seen))
93                          (graph-ref graph (car ls)))
94                  (cdr ls))
95          (cons (car ls) seen))))))
96
97(define (lock-pairs pairs)
98  (let lp ((ls pairs) (graph '()))
99    (cond
100     ((null? ls)
101      graph)
102     ((graph-reachable? (caar ls) (cdar ls) graph)
103      (lp (cdr ls) graph))
104     (else
105      (lp (cdr ls) (insert-edge (caar ls) (cdar ls) graph))))))
106
107(define (topological-sort graph)
108  (let visit ((ls graph) (seen '()) (res '()) (return (lambda (seen res) res)))
109    (cond
110     ((null? ls)
111      (return seen res))
112     ((member (car (car ls)) seen)
113      (visit (cdr ls) seen res return))
114     ((member (car (car ls)) res)
115      (visit (cdr ls) seen res return))
116     (else
117      (let scan-deps ((deps (cdr (car ls)))
118                      (seen (cons (car (car ls)) seen))
119                      (res res))
120        (cond
121         ((null? deps)
122          (visit (cdr ls) seen (cons (car (car ls)) res) return))
123         ((member (car deps) seen)
124          (scan-deps (cdr deps) seen res))
125         ((member (car deps) res)
126          (scan-deps (cdr deps) seen res))
127         ((assoc (car deps) graph)
128          => (lambda (vertices)
129               (visit (list vertices)
130                      seen
131                      res
132                      (lambda (seen res)
133                        (scan-deps (cdr deps) seen res)))))
134         (else
135          (scan-deps (cdr deps) seen (cons (car deps) res)))))))))
136
137(define (rank-votes votes)
138  (topological-sort (lock-pairs (map car (sort-pairs (tally-votes votes))))))
139
140;;; sample votes
141;; (define votes
142;;   '((member-a (A) (A-LITE) (SRFI) (B) (R5RS))
143;;     (member-b (B) (SRFI) (R5RS) (A-LITE) (A))
144;;     (member-c (SRFI) (A-LITE) (R5RS) (A B))
145;;     (member-d (R5RS) (A B SRFI A-LITE))
146;;     (member-e (A-LITE) (B) (A) (SRFI) (R5RS))
147;;     (member-f (A) (B) (A-LITE) (SRFI) (R5RS))
148;;     (member-g (B) (A-LITE) (A) (SRFI) (R5RS))
149;;     (member-h (A-LITE) (SRFI) (B) (A) (R5RS))
150;;     ))
151;;
152;; (rank-votes votes)