[Checkins] SVN: zope-foundation-admin/trunk/vote/stv.py counting
script.
Jim Fulton
cvs-admin at zope.org
Wed Jun 21 12:10:10 EDT 2006
Log message for revision 68777:
counting script.
Changed:
A zope-foundation-admin/trunk/vote/stv.py
-=-
Added: zope-foundation-admin/trunk/vote/stv.py
===================================================================
--- zope-foundation-admin/trunk/vote/stv.py 2006-06-21 11:26:57 UTC (rev 68776)
+++ zope-foundation-admin/trunk/vote/stv.py 2006-06-21 16:10:05 UTC (rev 68777)
@@ -0,0 +1,127 @@
+"""Single-transferable voting implementation
+
+As decribed at: http://en.wikipedia.org/wiki/Single_Transferable_Vote
+(On June 21, 2006)
+
+To run the example on the page, use:
+
+ python stv.py treats 3
+
+"""
+
+import os, random, sys
+
+def read(d):
+ data = []
+ for name in os.listdir(d):
+ data.append((1.0, open(os.path.join(d, name)).read().strip().split()))
+
+ random.shuffle(data)
+ print 'votes'
+ for w, vote in data:
+ print vote
+ print
+ return data
+
+def count(data, seats):
+ quota = len(data)/(seats+1) + 1
+ print 'quota', quota
+
+ candidates = {}
+ winners = {}
+ losers = {}
+ round = 1
+ while data:
+
+ # count votes
+ for weight, vote in data:
+ #print weight, vote
+ while vote:
+ candidate = vote.pop(0)
+ if candidate in winners:
+ continue
+ if candidate in losers:
+ continue
+
+ score, votes = candidates.get(candidate, (0.0, []))
+ score += weight
+ votes.append((weight, vote))
+ candidates[candidate] = score, votes
+ break
+
+ # find winners and harvest their alternate votes
+ data = []
+ for (candidate, (score, votes)) in candidates.items():
+ if score >= quota:
+ winners[candidate] = score
+ candidates.pop(candidate)
+ data.extend(
+ [((score-quota)/score * weight, vote)
+ for (weight, vote) in votes
+ if vote
+ ])
+
+ print
+ print 'round', round
+ round += 1
+ print ' winners', winners
+ print ' losers', losers
+ print ' candidates'
+ for i in candidates.items():
+ print ' ', i
+
+ if len(winners) >= seats:
+ print winners, [(c, s) for (c, (s, v)) in candidates.items()]
+ return
+
+
+ # If we don't have any votes to process from winners,
+ # then take the votes from the losingest loser
+ if not data and candidates:
+ # No winners in last round, so pick losingest loser
+ # and use their other votes.
+ score, candidate, data = sorted(
+ [(score, candidate, votes)
+ for (candidate, (score, votes)) in candidates.items()]
+ )[0]
+ losers[candidate] = score
+ candidates.pop(candidate)
+
+ print "Couldn't get enough winners. Here's what we have so far:"
+ print winners, [(c, s) for (c, (s, v)) in candidates.items()]
+
+
+def main(args=None):
+ if args == None:
+ args = sys.argv[1:]
+
+ d, seats = args
+ if d == 'treats':
+ data = [
+ (1.0, ['orange', 'tangerine']),
+ (1.0, ['orange', 'tangerine']),
+ (1.0, ['orange', 'tangerine']),
+ (1.0, ['orange', 'tangerine']),
+ (1.0, ['tangerine', 'orange']),
+ (1.0, ['tangerine', 'orange']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'strawberry']),
+ (1.0, ['chocolate', 'candy']),
+ (1.0, ['chocolate', 'candy']),
+ (1.0, ['chocolate', 'candy']),
+ (1.0, ['chocolate', 'candy']),
+ (1.0, ['strawberry']),
+ (1.0, ['candy']),
+ ]
+ else:
+ data = read(d)
+ count(data, int(seats))
+
+if __name__ == '__main__':
+ main()
More information about the Checkins
mailing list