Revision 79948f90 stv.py
b/stv.py | ||
---|---|---|
61 | 61 |
decreasing order of preference) and an ordered list of weights |
62 | 62 |
(new weights are added to the front of the list). The index of the |
63 | 63 |
current preference (for the first count and subsequent rounds) |
64 |
is kept in an index.
|
|
64 |
is also kept.
|
|
65 | 65 |
|
66 | 66 |
""" |
67 | 67 |
|
68 | 68 |
candidates = [] |
69 | 69 |
weights = [1.0] |
70 |
index = 0
|
|
70 |
current_preference = 0
|
|
71 | 71 |
_value = 1.0 |
72 | 72 |
|
73 | 73 |
def __init__(self, candidates=[]): |
... | ... | |
135 | 135 |
|
136 | 136 |
logger = logging.getLogger(SVT_LOGGER) |
137 | 137 |
transferred = [] |
138 |
# Keep a hash of ballot moves for logging purposes. |
|
139 |
# The hash comprises |
|
138 | 140 |
moves = {} |
139 | 141 |
|
140 | 142 |
for ballot in allocated[selected]: |
141 | 143 |
reallocated = False |
142 |
i = ballot.index + 1
|
|
144 |
i = ballot.current_preference + 1
|
|
143 | 145 |
while not reallocated and i < len(ballot.candidates): |
144 | 146 |
recipient = ballot.candidates[i] |
145 | 147 |
if recipient in hopefuls: |
146 |
ballot.index = i
|
|
148 |
ballot.current_preference = i
|
|
147 | 149 |
ballot.add_weight(weight) |
150 |
current_value = ballot.get_value() |
|
148 | 151 |
if recipient in allocated: |
149 | 152 |
allocated[recipient].append(ballot) |
150 | 153 |
else: |
151 | 154 |
allocated[recipient] = [ballot] |
152 | 155 |
if recipient in vote_count: |
153 |
vote_count[recipient] += (1 * weight)
|
|
156 |
vote_count[recipient] += current_value
|
|
154 | 157 |
else: |
155 |
vote_count[recipient] = 1 * weight |
|
158 |
vote_count[recipient] = current_value |
|
159 |
vote_count[selected] -= current_value |
|
156 | 160 |
reallocated = True |
157 |
if (selected, recipient) in moves: |
|
158 |
moves[(selected, recipient)] += 1 |
|
161 |
if (selected, recipient, current_value) in moves:
|
|
162 |
moves[(selected, recipient, current_value)] += 1
|
|
159 | 163 |
else: |
160 |
moves[(selected, recipient)] = 1 |
|
164 |
moves[(selected, recipient, current_value)] = 1
|
|
161 | 165 |
transferred.append(ballot) |
162 | 166 |
else: |
163 | 167 |
i += 1 |
164 | 168 |
for move, times in moves.iteritems(): |
165 |
description = "from {0} to {1} {2}*{3}={4}".format(move[0], move[1], |
|
169 |
description = "from {0} to {1} {2}*{3}={4}".format(move[0], |
|
170 |
move[1], |
|
166 | 171 |
times, |
167 |
weight,
|
|
168 |
times*weight)
|
|
172 |
move[2],
|
|
173 |
times*move[2])
|
|
169 | 174 |
logger.info(LOG_MESSAGE.format(action=Action.TRANSFER, |
170 | 175 |
desc=description)) |
171 | 176 |
allocated[selected][:] = [x for x in allocated[selected] |
172 | 177 |
if x not in transferred ] |
173 |
vote_count[selected] -= (len(transferred) * weight) |
|
174 | 178 |
|
175 | 179 |
def count_stv(ballots, seats, rnd_gen=None): |
176 | 180 |
"""Performs a SVT vote for the given ballots and number of seats. |
... | ... | |
185 | 189 |
|
186 | 190 |
seed() |
187 | 191 |
|
188 |
threshold = int(math.ceil(1 + len(ballots) / (seats + 1)))
|
|
192 |
threshold = (1 + len(ballots) / (seats + 1))
|
|
189 | 193 |
|
190 | 194 |
logger = logging.getLogger(SVT_LOGGER) |
191 | 195 |
logger.info(LOG_MESSAGE.format(action=Action.THRESHOLD, |
... | ... | |
267 | 271 |
parser = argparse.ArgumentParser(description='Perform STV') |
268 | 272 |
parser.add_argument('--ballots', nargs='?', default='sys.stdin', |
269 | 273 |
dest='ballots_file', help='input ballots file') |
274 |
parser.add_argument('--seats', nargs='?', default=0, |
|
275 |
dest='seats', help='number of seats') |
|
270 | 276 |
args = parser.parse_args() |
271 | 277 |
ballots = [] |
272 | 278 |
ballots_file = sys.stdin |
... | ... | |
278 | 284 |
for ballot in ballots_reader: |
279 | 285 |
ballots.append(Ballot(ballot)) |
280 | 286 |
|
281 |
(elected, vote_count) = count_stv(ballots, 5) |
|
287 |
if args.seats == 0: |
|
288 |
args.seats = len(ballots) / 2 |
|
289 |
(elected, vote_count) = count_stv(ballots, int(args.seats)) |
|
282 | 290 |
|
283 | 291 |
print "Results:" |
284 | 292 |
for candidate in elected: |
Also available in: Unified diff