Probability Models¶
To generate profiles, we use the Preflib.org tools available at https://github.com/PrefLib/PrefLib-Tools.
Impartial (Anonymous) Culture¶
IC: Impartial Culture Model - generate a profile by sampling from a uniform distribution over profiles with \(n\) candidates and \(m\) voters.
IAC: Impartial Anonymous Culture Model - generate a profile by sampling from a uniform distribution over anonymous profiles with \(n\) candidates and \(m\) voters.
INAC: Impartial Anonymous and Neutral Culture Model
O. Egecioglu and A. Giritligil (2013). The Impartial, Anonymous, and Neutral Culture Model: A Probability Model for Sampling Public Preference Structures, Journal of Mathematical Sociology, 37: pp. 203 - 222
# import the Profile class
from voting.profiles import Profile
from voting.generate_profiles import *
from voting.voting_methods import *
import networkx as nx
from itertools import combinations
import matplotlib.pyplot as plt
import pickle
import random
from tqdm.notebook import tqdm
pm="IC"
num_trials = 1000
num_candidates = 5
num_voters = 1001
num_condorcet_winner = 0
num_cycles = 0
for t in range(num_trials):
prof = generate_profile(num_candidates, num_voters, probmod = pm)
num_condorcet_winner += prof.condorcet_winner() is not None
num_cycles += has_cycle(prof.margin_graph())
print(f"{round(num_condorcet_winner / num_trials, 2) *100}% of profiles have a Condorcet winner.")
print(f"{round(num_cycles / num_trials, 2) *100}% of profiles have a majority cycle.")
74.0% of profiles have a Condorcet winner.
49.0% of profiles have a majority cycle.
pm="IAC"
num_trials = 1000
num_candidates = 5
num_voters = 1001
num_condorcet_winner = 0
num_cycles = 0
for t in range(num_trials):
prof = generate_profile(num_candidates, num_voters, probmod = pm)
num_condorcet_winner += prof.condorcet_winner() is not None
num_cycles += has_cycle(prof.margin_graph())
print(f"{round(num_condorcet_winner / num_trials, 2) *100}% of profiles have a Condorcet winner.")
print(f"{round(num_cycles / num_trials, 2) * 100}% of profiles have a majority cycle.")
75.0% of profiles have a Condorcet winner.
47.0% of profiles have a majority cycle.
%%time
SKIP_SIMULATION = True
if not SKIP_SIMULATION:
all_num_candidates = [3, 4, 5, 6, 10]
all_num_voters = [10, 11, 100, 101, 1000, 1001]
num_trials = 25000
voting_scenarios = list(product(all_num_candidates, all_num_voters))
data = {vs:
{
"perc_condorcet_winners": {"IC": 0, "IAC": 0},
"perc_cycles": {"IC": 0, "IAC": 0},
}
for vs in voting_scenarios
}
for nc, nv in tqdm(voting_scenarios):
num_condorcet_winner_IC = 0
num_condorcet_winner_IAC = 0
num_cycle_IC = 0
num_cycle_IAC = 0
for t in range(num_trials):
prof_IC = generate_profile(nc, nv, probmod="IC")
prof_IAC = generate_profile(nc, nv, probmod="IAC")
num_condorcet_winner_IC += prof_IC.condorcet_winner() is not None
num_cycle_IC += has_cycle(prof_IC.margin_graph())
num_condorcet_winner_IAC += prof_IAC.condorcet_winner() is not None
num_cycle_IAC += has_cycle(prof_IAC.margin_graph())
data[(nc, nv)]["perc_condorcet_winners"]["IC"] = num_condorcet_winner_IC / num_trials
data[(nc, nv)]["perc_cycles"]["IC"] = num_cycle_IC / num_trials
data[(nc, nv)]["perc_condorcet_winners"]["IAC"] = num_condorcet_winner_IAC / num_trials
data[(nc, nv)]["perc_cycles"]["IAC"] = num_cycle_IAC / num_trials
pickle.dump(data, open("condorcet_data.pkl", "wb"))
CPU times: user 2 µs, sys: 1 µs, total: 3 µs
Wall time: 4.05 µs
import tabulate
if SKIP_SIMULATION:
data = pickle.load(open("condorcet_data.pkl", "rb"))
all_num_candidates = [3, 4, 5, 6, 10]
all_num_voters = [10, 11, 100, 101, 1000, 1001]
table = list()
headers = list()
for nc in all_num_candidates:
row = [nc]
for nv in all_num_voters:
row.append(f"{round(data[(nc, nv)]['perc_condorcet_winners']['IC'],2)}, {round(data[(nc, nv)]['perc_condorcet_winners']['IAC'],2)}")
table.append(row)
headers = [str(nv) for nv in all_num_voters]
print(tabulate.tabulate(table, headers, tablefmt="github"))
| | 10 | 11 | 100 | 101 | 1000 | 1001 |
|----|------------|------------|------------|------------|------------|------------|
| 3 | 0.58, 0.73 | 0.92, 0.94 | 0.79, 0.91 | 0.91, 0.94 | 0.87, 0.94 | 0.91, 0.94 |
| 4 | 0.47, 0.54 | 0.84, 0.85 | 0.69, 0.78 | 0.82, 0.84 | 0.78, 0.83 | 0.83, 0.84 |
| 5 | 0.39, 0.41 | 0.77, 0.77 | 0.61, 0.65 | 0.75, 0.75 | 0.7, 0.74 | 0.75, 0.75 |
| 6 | 0.34, 0.34 | 0.71, 0.71 | 0.54, 0.56 | 0.69, 0.68 | 0.64, 0.66 | 0.68, 0.68 |
| 10 | 0.21, 0.21 | 0.55, 0.55 | 0.39, 0.38 | 0.52, 0.52 | 0.47, 0.47 | 0.51, 0.51 |
Urn Model¶
In the Polya-Eggenberger urn model, each voter in turn randomly draws a linear order from an urn. Initially the urn is \(\mathcal{L}(X)\). If a voter randomly chooses \(L\) from the urn, we return \(L\) to the urn plus \(\alpha\in\mathbb{N}\) copies of \(L\).
IC is the special case where \(\alpha=0\).
IAC is the special case where \(\alpha=1\).
print("Generated by the URN model with alpha = 0")
prof = generate_profile(4, 5, probmod="URN", probmod_param=0)
prof.display()
print("Generated by the URN model with alpha = 1")
prof = generate_profile(4, 5, probmod="URN", probmod_param=1)
prof.display()
print("Generate by URN model with alpha = 10")
prof = generate_profile(4, 5, probmod="URN", probmod_param=10)
prof.display()
print("Generate by URN model with alpha = 100")
prof = generate_profile(4, 5, probmod="URN", probmod_param=100)
prof.display()
Generated by the URN model with alpha = 0
+---+---+---+---+
| 2 | 1 | 1 | 1 |
+---+---+---+---+
| 1 | 2 | 3 | 3 |
| 0 | 3 | 2 | 0 |
| 3 | 1 | 1 | 1 |
| 2 | 0 | 0 | 2 |
+---+---+---+---+
Generated by the URN model with alpha = 1
+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+
| 1 | 0 | 0 | 3 | 2 |
| 2 | 3 | 2 | 1 | 3 |
| 0 | 1 | 1 | 2 | 0 |
| 3 | 2 | 3 | 0 | 1 |
+---+---+---+---+---+
Generate by URN model with alpha = 10
+---+---+---+
| 2 | 2 | 1 |
+---+---+---+
| 3 | 0 | 3 |
| 0 | 3 | 0 |
| 1 | 2 | 2 |
| 2 | 1 | 1 |
+---+---+---+
Generate by URN model with alpha = 100
+---+
| 5 |
+---+
| 0 |
| 3 |
| 1 |
| 2 |
+---+
## from preflib tools ###
# Generate votes based on the URN Model..
# we need numvotes with replace replacements.
def gen_urn(numvotes, replace, alts):
voteMap = {}
ReplaceVotes = {}
ICsize = math.factorial(len(alts))
print("ICsize ", ICsize)
ReplaceSize = 0
for x in range(numvotes):
print("initially voteMap is", voteMap)
print("initially ReplaceVotes is", ReplaceVotes)
flip = random.randint(1, ICsize+ReplaceSize)
print("flip:", flip)
if flip <= ICsize:
#generate an IC vote and make a suitable number of replacements...
print("flip less than ICsize, so generate a new ranking")
tvote = tuple(np.random.permutation(len(alts))) # gen_ic_vote(alts)
voteMap[tvote] = (voteMap.get(tvote, 0) + 1)
ReplaceVotes[tvote] = (ReplaceVotes.get(tvote, 0) + replace)
ReplaceSize += replace
print("ReplaceSize", ReplaceSize)
print("made " + str(tvote))
else:
print("find the ranking from ReplaceVote ")
#iterate over replacement hash and select proper vote.
flip = flip - ICsize
for vote in ReplaceVotes.keys():
print("testing ", vote)
flip = flip - ReplaceVotes[vote]
print("flip is now", flip)
if flip <= 0:
print("Found the ranking")
voteMap[vote] = (voteMap.get(vote, 0) + 1)
ReplaceVotes[vote] = (ReplaceVotes.get(vote, 0) + replace)
ReplaceSize += replace
break
else:
print("We Have a problem... replace fell through....")
exit()
print("now, voteMap is", voteMap)
print("now, ReplaceVotes is", ReplaceVotes)
print("======\n")
return voteMap
# Return a TUPLE! IC vote given a vector of alternatives.
def gen_ic_vote(alts):
options = list(alts)
vote = []
while(len(options) > 0):
#randomly select an option
vote.append(options.pop(random.randint(0,len(options)-1)))
return tuple(vote)
gen_urn(5,1,[0,1,2,3])
ICsize 24
initially voteMap is {}
initially ReplaceVotes is {}
flip: 18
flip less than ICsize, so generate a new ranking
ReplaceSize 1
made (2, 3, 1, 0)
now, voteMap is {(2, 3, 1, 0): 1}
now, ReplaceVotes is {(2, 3, 1, 0): 1}
======
initially voteMap is {(2, 3, 1, 0): 1}
initially ReplaceVotes is {(2, 3, 1, 0): 1}
flip: 18
flip less than ICsize, so generate a new ranking
ReplaceSize 2
made (2, 3, 1, 0)
now, voteMap is {(2, 3, 1, 0): 2}
now, ReplaceVotes is {(2, 3, 1, 0): 2}
======
initially voteMap is {(2, 3, 1, 0): 2}
initially ReplaceVotes is {(2, 3, 1, 0): 2}
flip: 12
flip less than ICsize, so generate a new ranking
ReplaceSize 3
made (2, 0, 3, 1)
now, voteMap is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1}
now, ReplaceVotes is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1}
======
initially voteMap is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1}
initially ReplaceVotes is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1}
flip: 14
flip less than ICsize, so generate a new ranking
ReplaceSize 4
made (3, 1, 0, 2)
now, voteMap is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
now, ReplaceVotes is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
======
initially voteMap is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
initially ReplaceVotes is {(2, 3, 1, 0): 2, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
flip: 26
find the ranking from ReplaceVote
testing (2, 3, 1, 0)
flip is now 0
Found the ranking
now, voteMap is {(2, 3, 1, 0): 3, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
now, ReplaceVotes is {(2, 3, 1, 0): 3, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
======
{(2, 3, 1, 0): 3, (2, 0, 3, 1): 1, (3, 1, 0, 2): 1}
Mallows Model¶
In the Mallow’s model, given a reference ranking \(L_0\in\mathcal{L}(X)\) and \(\phi\in (0,1]\), the probability that a voter’s ballot is \(L\in\mathcal{L}(X)\) is \(Pr_{L_0}(L)=\phi^{\tau(L,L_0)}/C\) where \(\tau(L,L_0)= {{|X|}\choose{2}} - |L\cap L_0|\), the Kendell-tau distance of \(L\) to \(L_0\), and \(C\) is a normalization constant.
The Kendal-tau distance, also known as the swap distance, between rankings \(R_1\) and \(R_2\) is the minimal number of swaps of adjacent candidates needed to turn vote \(R_1\) into vote \(R_2\).
E.g., the rankings \(a\ b\ c\ d\) and \(a\ d\ b\ c\) has a swap distance of 2.
IC is the special case where \(\phi=1\).
MALLOWS_2REF: Consider an ordering \(L_0\) and its converse \(L_0^{-1}\) (e.g., \(L_0\) ranks candidates from more liberal to more conservative, and \(L_0^{-1}\) vice versa), in which case the probability that a voter’s ballot is \(L\) is \(\frac{1}{2} Pr_{L_0}(L)+\frac{1}{2}Pr_{L_0^{-1}}(L)\).
import random
# For Phi and a given number of candidates, compute the
# insertion probability vectors.
def compute_mallows_insertvec_dist(ncand, phi):
#Compute the Various Mallows Probability Distros
vec_dist = {}
for i in range(1, ncand+1):
#Start with an empty distro of length i
dist = [0] * i
#compute the denom = phi^0 + phi^1 + ... phi^(i-1)
denom = sum([pow(phi,k) for k in range(i)])
#Fill each element of the distro with phi^i-j / denom
for j in range(1, i+1):
dist[j-1] = pow(phi, i - j) / denom
#print(str(dist) + "total: " + str(sum(dist)))
vec_dist[i] = dist
return vec_dist
# Return a value drawn from a particular distribution.
def draw(values, distro):
#Return a value randomly from a given discrete distribution.
#This is a bit hacked together -- only need that the distribution
#sums to 1.0 within 5 digits of rounding.
if round(sum(distro),5) != 1.0:
print("Input Distro is not a Distro...")
print(str(distro) + " Sum: " + str(sum(distro)))
exit()
if len(distro) != len(values):
print("Values and Distro have different length")
cv = 0
draw = random.random() - distro[cv]
while draw > 0.0:
cv+= 1
draw -= distro[cv]
return values[cv]
# Generate a Mallows model with the various mixing parameters passed in
# nvoters is the number of votes we need
# candmap is a candidate map
# mix is an array such that sum(mix) == 1 and describes the distro over the models
# phis is an array len(phis) = len(mix) = len(refs) that is the phi for the particular model
# refs is an array of dicts that describe the reference ranking for the set.
def gen_mallows(nvoters, candmap, mix, phis, refs):
if len(mix) != len(phis) or len(phis) != len(refs):
print("Mix != Phis != Refs")
exit()
print("refs is", refs)
#Precompute the distros for each Phi and Ref.
#Turn each ref into an order for ease of use...
m_insert_dists = []
for i in range(len(mix)):
m_insert_dists.append(compute_mallows_insertvec_dist(len(candmap), phis[i]))
print("m_insert_dists", m_insert_dists)
#Now, generate votes...
votemap = {}
for cvoter in range(nvoters):
cmodel = draw(list(range(len(mix))), mix)
print("cmodel is ", cmodel)
#Generate a vote for the selected model
insvec = [0] * len(candmap)
for i in range(1, len(insvec)+1):
#options are 1...max
print("i is ", i)
print("Options: " + str(list(range(1, i+1))))
print("Drawing on model " + str(cmodel))
print("Dist: " + str(m_insert_dists[cmodel][i]))
print("range ", list(range(1, i+1)))
insvec[i-1] = draw(list(range(1, i+1)), m_insert_dists[cmodel][i])
print("choice is ", insvec[i-1])
print("--\n")
print("\ninsvec is ", insvec,"\n")
vote = []
for i in range(len(refs[cmodel])):
print("i is ", i)
print("refs is ", refs[cmodel])
print("building vote ", refs[cmodel][i])
#print("building vote insvec[i] - 1", insvec[i]-1)
vote.insert(insvec[i]-1, refs[cmodel][i])
print("vote is ", vote)
print("++++\n")
print("mallows vote: " + str(vote))
tvote = tuple(vote)
votemap[tuple(vote)] = votemap.get(tuple(vote), 0) + 1
print("-------\n")
return votemap
num_cands = 4
num_voters = 2
phis = [1.0]
cmap = {cn:cn for cn in range(num_cands)}
print(cmap)
print(gen_mallows(num_voters,
cmap,
[1.0],
phis,
[{0:3, 1:1, 2:0, 3:2}]))
{0: 0, 1: 1, 2: 2, 3: 3}
refs is [{0: 3, 1: 1, 2: 0, 3: 2}]
m_insert_dists [{1: [1.0], 2: [0.5, 0.5], 3: [0.3333333333333333, 0.3333333333333333, 0.3333333333333333], 4: [0.25, 0.25, 0.25, 0.25]}]
cmodel is 0
i is 1
Options: [1]
Drawing on model 0
Dist: [1.0]
range [1]
choice is 1
--
i is 2
Options: [1, 2]
Drawing on model 0
Dist: [0.5, 0.5]
range [1, 2]
choice is 2
--
i is 3
Options: [1, 2, 3]
Drawing on model 0
Dist: [0.3333333333333333, 0.3333333333333333, 0.3333333333333333]
range [1, 2, 3]
choice is 2
--
i is 4
Options: [1, 2, 3, 4]
Drawing on model 0
Dist: [0.25, 0.25, 0.25, 0.25]
range [1, 2, 3, 4]
choice is 3
--
insvec is [1, 2, 2, 3]
i is 0
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 3
vote is [3]
++++
i is 1
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 1
vote is [3, 1]
++++
i is 2
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 0
vote is [3, 0, 1]
++++
i is 3
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 2
vote is [3, 0, 2, 1]
++++
mallows vote: [3, 0, 2, 1]
-------
cmodel is 0
i is 1
Options: [1]
Drawing on model 0
Dist: [1.0]
range [1]
choice is 1
--
i is 2
Options: [1, 2]
Drawing on model 0
Dist: [0.5, 0.5]
range [1, 2]
choice is 2
--
i is 3
Options: [1, 2, 3]
Drawing on model 0
Dist: [0.3333333333333333, 0.3333333333333333, 0.3333333333333333]
range [1, 2, 3]
choice is 1
--
i is 4
Options: [1, 2, 3, 4]
Drawing on model 0
Dist: [0.25, 0.25, 0.25, 0.25]
range [1, 2, 3, 4]
choice is 3
--
insvec is [1, 2, 1, 3]
i is 0
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 3
vote is [3]
++++
i is 1
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 1
vote is [3, 1]
++++
i is 2
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 0
vote is [0, 3, 1]
++++
i is 3
refs is {0: 3, 1: 1, 2: 0, 3: 2}
building vote 2
vote is [0, 3, 2, 1]
++++
mallows vote: [0, 3, 2, 1]
-------
{(3, 0, 2, 1): 1, (0, 3, 2, 1): 1}
print("Generated by the MALLOWS model with phi = 0")
prof = generate_profile(4, 5, probmod="MALLOWS", probmod_param=0)
prof.display()
print("Generated by the MALLOWS model with phi = 0.1")
prof = generate_profile(4, 5, probmod="MALLOWS", probmod_param=0.1)
prof.display()
print("Generated by the MALLOWS model with phi = 0.5")
prof = generate_profile(4, 5, probmod="MALLOWS", probmod_param=0.5)
prof.display()
print("Generated by the MALLOWS model with phi = 0.8")
prof = generate_profile(4, 5, probmod="MALLOWS", probmod_param=0.8)
prof.display()
print("Generated by the MALLOWS model with phi = 1")
prof = generate_profile(4, 5, probmod="MALLOWS", probmod_param=1.0)
prof.display()
Generated by the MALLOWS model with phi = 0
+---+
| 5 |
+---+
| 2 |
| 0 |
| 3 |
| 1 |
+---+
Generated by the MALLOWS model with phi = 0.1
+---+---+
| 1 | 4 |
+---+---+
| 1 | 1 |
| 2 | 0 |
| 0 | 2 |
| 3 | 3 |
+---+---+
Generated by the MALLOWS model with phi = 0.5
+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+
| 2 | 2 | 3 | 2 | 3 |
| 0 | 1 | 2 | 3 | 1 |
| 1 | 3 | 1 | 1 | 2 |
| 3 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+
Generated by the MALLOWS model with phi = 0.8
+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+
| 1 | 3 | 2 | 0 | 1 |
| 3 | 1 | 0 | 1 | 3 |
| 0 | 2 | 3 | 2 | 2 |
| 2 | 0 | 1 | 3 | 0 |
+---+---+---+---+---+
Generated by the MALLOWS model with phi = 1
+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+
| 3 | 0 | 1 | 0 | 2 |
| 1 | 2 | 0 | 2 | 3 |
| 0 | 3 | 2 | 1 | 0 |
| 2 | 1 | 3 | 3 | 1 |
+---+---+---+---+---+
Single Peaked¶
# Return a Tuple for a IC-Single Peaked... with alternatives in range 1....range.
def gen_icsp_single_vote(alts):
a = 0
b = len(alts)-1
temp = []
while a != b:
print(f"a={a}, b={b}")
if random.randint(0,1) == 1:
temp.append(alts[a])
a+= 1
else:
temp.append(alts[b])
b -= 1
print("temp is ", temp)
temp.append(alts[a])
print(temp)
print("-----\n")
return tuple(temp[::-1]) # reverse
def gen_single_peaked_impartial_culture_strict(nvotes, alts):
voteset = {}
for i in range(nvotes):
tvote = gen_icsp_single_vote(alts)
voteset[tvote] = voteset.get(tvote, 0) + 1
return voteset
num_cands = 4
num_voters = 1
vs = gen_single_peaked_impartial_culture_strict(num_voters, list(range(num_cands)))
prof = Profile([v[0] for v in vs.items()], num_cands, rcounts = [v[1] for v in vs.items()])
prof.display()
a=0, b=3
temp is [3]
a=0, b=2
temp is [3, 0]
a=1, b=2
temp is [3, 0, 1]
[3, 0, 1, 2]
-----
+---+
| 1 |
+---+
| 2 |
| 1 |
| 0 |
| 3 |
+---+
Spatial Model¶
S. Merrill, III (1993). Voting behavior under the directional spatial model of electoral competition, Public Choice 77, pp. 739 - 756.
def voter_utility(v_pos, c_pos, beta):
'''Based on the Rabinowitz and Macdonald (1989) mixed model
described in Section 3, pp. 745 - 747 of
"Voting behavior under the directional spatial model of electoral competition" by S. Merrill III
beta = 1 is the proximity model
beta = 0 is the directional model
'''
return 2 * np.dot(v_pos, c_pos) - beta*(np.linalg.norm(v_pos)**2 + np.linalg.norm(c_pos)**2)
def create_prof_spatial_model2(num_voters, cmap, params):
num_dim = params[0] # the first component of the parameter is the number of dimensions
beta = params[1] # used to define the mixed model: beta = 1 is proximity model (i.e., Euclidean distance)
num_cands = len(cmap.keys())
mean = [0] * num_dim # mean is 0 for each dimension
cov = np.diag([1]*num_dim) # diagonal covariance
# sample candidate/voter positions using a multivariate normal distribution
cand_positions = np.random.multivariate_normal(np.array(mean), cov, num_cands)
voter_positions = np.random.multivariate_normal(np.array(mean), cov, num_voters)
# generate the rankings and counts for each ranking
ranking_counts = dict()
for v,v_pos in enumerate(voter_positions):
v_utils = {voter_utility(v_pos,c_pos,beta): c for c,c_pos in enumerate(cand_positions)}
ranking = tuple([v_utils[_u] for _u in sorted(v_utils.keys(),reverse=True)])
if ranking in ranking_counts.keys():
ranking_counts[ranking] += 1
else:
ranking_counts.update({ranking:1})
# list of tuples where first component is a ranking and the second is the count
prof_counts = ranking_counts.items()
return [rc[0] for rc in prof_counts], [rc[1] for rc in prof_counts], list(voter_positions), list(cand_positions)
num_cands = 4
beta = 0.5
dim = 2
rankings,rcounts,voter_positions, cand_positions = create_prof_spatial_model2(10,
{c:c for c in range(num_cands)},
[dim, beta])
prof = Profile(rankings, num_cands, rcounts=rcounts)
prof.display()
plt.scatter([v[0] for v in voter_positions], [v[1] for v in voter_positions], color='blue', marker='x')
plt.scatter([c[0] for c in cand_positions], [c[1] for c in cand_positions], color='red', marker='o')
for c_idx,c in enumerate(cand_positions):
print(f"the utility of {c_idx} is {voter_utility(voter_positions[0], c, beta)}")
for c_idx,c in enumerate(cand_positions):
plt.text(c[0]+0.05, c[1], c_idx)
plt.show()
+---+---+---+---+---+---+---+
| 4 | 1 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+---+---+
| 0 | 3 | 0 | 3 | 0 | 1 | 2 |
| 3 | 1 | 2 | 0 | 1 | 3 | 1 |
| 1 | 0 | 1 | 1 | 3 | 2 | 0 |
| 2 | 2 | 3 | 2 | 2 | 0 | 3 |
+---+---+---+---+---+---+---+
the utility of 0 is 0.8206607636468788
the utility of 1 is -9.739953582971768
the utility of 2 is -11.897181276651917
the utility of 3 is -6.84479901593228

num_cands = 4
beta = 1.0
dim = 2
rankings,rcounts,voter_positions, cand_positions = create_prof_spatial_model2(10,
{c:c for c in range(num_cands)},
[dim, beta])
prof = Profile(rankings, num_cands, rcounts=rcounts)
prof.display()
plt.scatter([v[0] for v in voter_positions], [v[1] for v in voter_positions], color='blue', marker='x')
plt.scatter([c[0] for c in cand_positions], [c[1] for c in cand_positions], color='red', marker='o')
plt.scatter([0], [0], color='black', marker='o')
for c_idx,c in enumerate(cand_positions):
print(f"the utility of {c_idx} is {voter_utility(voter_positions[0], c, beta)}")
for c_idx,c in enumerate(cand_positions):
plt.text(c[0]+0.05, c[1], c_idx)
plt.show()
+---+---+---+---+---+---+---+
| 1 | 1 | 1 | 1 | 3 | 2 | 1 |
+---+---+---+---+---+---+---+
| 0 | 0 | 1 | 3 | 2 | 2 | 3 |
| 2 | 2 | 2 | 0 | 0 | 1 | 0 |
| 1 | 3 | 0 | 1 | 1 | 0 | 2 |
| 3 | 1 | 3 | 2 | 3 | 3 | 1 |
+---+---+---+---+---+---+---+
the utility of 0 is -0.027117624640677906
the utility of 1 is -5.9297618918464154
the utility of 2 is -1.9338526458379373
the utility of 3 is -6.667671843756489

Real Elections¶
import glob
election_data_directory = './election-data/'
# read the file containing election data and return a profile
def read_election_data(fname):
with open(fname, 'r') as fp:
line = fp.readline()
num_cands = int(line)
remaining_lines = fp.readlines()
num_rankings = remaining_lines[num_cands]
rankings_data = remaining_lines[num_cands + 1:]
anon_prof = {}
rankings = list()
rcounts = list()
for r in rankings_data:
_ranking = r.split(',')
num = int(_ranking[0])
rankings.append(tuple([int(_.strip()) - 1 for _ in _ranking[1:num_cands+1]]))
rcounts.append(num)
return Profile(rankings, num_cands, rcounts = rcounts)
prof = read_election_data(f"{election_data_directory}ED-00025-00000002.soc")
prof.display()
prof.condorcet_winner()
+-----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+
| 200 | 86 | 69 | 45 | 42 | 35 | 34 | 28 | 27 | 22 | 20 | 19 | 19 | 18 | 18 | 17 | 17 | 16 | 15 | 14 | 12 | 10 | 6 | 6 |
+-----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+
| 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 2 | 1 | 1 | 3 | 2 | 1 | 2 | 3 | 2 | 3 | 2 | 3 | 2 | 3 | 3 |
| 1 | 1 | 2 | 0 | 3 | 2 | 0 | 3 | 2 | 0 | 3 | 3 | 0 | 3 | 2 | 1 | 1 | 1 | 0 | 0 | 1 | 3 | 2 | 2 |
| 2 | 3 | 1 | 2 | 1 | 0 | 3 | 2 | 3 | 1 | 0 | 2 | 1 | 0 | 3 | 0 | 2 | 3 | 2 | 3 | 0 | 1 | 1 | 0 |
| 3 | 2 | 3 | 3 | 2 | 3 | 2 | 1 | 1 | 3 | 2 | 0 | 2 | 1 | 0 | 3 | 0 | 0 | 1 | 1 | 2 | 0 | 0 | 1 |
+-----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+
0
num_elections = 0
num_condorcet_winner = 0
num_cycle = 0
for fname in glob.glob(election_data_directory + "/*.soc"):
num_elections += 1
prof = read_election_data(fname)
print(f"Election {num_elections}")
print("\tNumber of candidates: ", prof.num_cands)
print("\tNumber of voters: ", prof.num_voters)
num_condorcet_winner += prof.condorcet_winner() is not None
num_cycle += has_cycle(prof.margin_graph())
print(f"Out of {num_elections} elections:")
print(f"\t{round(num_condorcet_winner / num_elections, 4)*100}% have a Condorcet winner")
print(f"\t{round(num_cycle / num_elections, 4)*100}% have a cycle in the majority graph")
Election 1
Number of candidates: 30
Number of voters: 7
Election 2
Number of candidates: 4
Number of voters: 362
Election 3
Number of candidates: 4
Number of voters: 1256
Election 4
Number of candidates: 4
Number of voters: 369
Election 5
Number of candidates: 32
Number of voters: 4
Election 6
Number of candidates: 60
Number of voters: 4
Election 7
Number of candidates: 131
Number of voters: 4
Election 8
Number of candidates: 3
Number of voters: 405
Election 9
Number of candidates: 3
Number of voters: 779
Election 10
Number of candidates: 3
Number of voters: 1377
Election 11
Number of candidates: 3
Number of voters: 496
Election 12
Number of candidates: 3
Number of voters: 963
Election 13
Number of candidates: 3
Number of voters: 440
Election 14
Number of candidates: 70
Number of voters: 4
Election 15
Number of candidates: 52
Number of voters: 4
Election 16
Number of candidates: 81
Number of voters: 4
Election 17
Number of candidates: 4
Number of voters: 643
Election 18
Number of candidates: 3
Number of voters: 440
Election 19
Number of candidates: 4
Number of voters: 494
Election 20
Number of candidates: 4
Number of voters: 382
Election 21
Number of candidates: 4
Number of voters: 387
Election 22
Number of candidates: 18
Number of voters: 4
Election 23
Number of candidates: 73
Number of voters: 4
Election 24
Number of candidates: 3
Number of voters: 1063
Election 25
Number of candidates: 3
Number of voters: 751
Election 26
Number of candidates: 3
Number of voters: 1117
Election 27
Number of candidates: 3
Number of voters: 490
Election 28
Number of candidates: 3
Number of voters: 363
Election 29
Number of candidates: 3
Number of voters: 982
Election 30
Number of candidates: 44
Number of voters: 4
Election 31
Number of candidates: 100
Number of voters: 4
Election 32
Number of candidates: 4
Number of voters: 518
Election 33
Number of candidates: 4
Number of voters: 411
Election 34
Number of candidates: 20
Number of voters: 9
Election 35
Number of candidates: 4
Number of voters: 494
Election 36
Number of candidates: 4
Number of voters: 422
Election 37
Number of candidates: 40
Number of voters: 4
Election 38
Number of candidates: 21
Number of voters: 4
Election 39
Number of candidates: 3
Number of voters: 695
Election 40
Number of candidates: 3
Number of voters: 397
Election 41
Number of candidates: 3
Number of voters: 417
Election 42
Number of candidates: 3
Number of voters: 382
Election 43
Number of candidates: 3
Number of voters: 1008
Election 44
Number of candidates: 3
Number of voters: 383
Election 45
Number of candidates: 23
Number of voters: 4
Election 46
Number of candidates: 28
Number of voters: 4
Election 47
Number of candidates: 4
Number of voters: 473
Election 48
Number of candidates: 4
Number of voters: 718
Election 49
Number of candidates: 9
Number of voters: 146
Election 50
Number of candidates: 4
Number of voters: 588
Election 51
Number of candidates: 4
Number of voters: 431
Election 52
Number of candidates: 4
Number of voters: 625
Election 53
Number of candidates: 77
Number of voters: 4
Election 54
Number of candidates: 32
Number of voters: 4
Election 55
Number of candidates: 41
Number of voters: 4
Election 56
Number of candidates: 3
Number of voters: 367
Election 57
Number of candidates: 3
Number of voters: 547
Election 58
Number of candidates: 3
Number of voters: 563
Election 59
Number of candidates: 3
Number of voters: 1538
Election 60
Number of candidates: 3
Number of voters: 368
Election 61
Number of candidates: 3
Number of voters: 2704
Election 62
Number of candidates: 12
Number of voters: 4
Election 63
Number of candidates: 45
Number of voters: 4
Election 64
Number of candidates: 26
Number of voters: 4
Election 65
Number of candidates: 4
Number of voters: 362
Election 66
Number of candidates: 4
Number of voters: 390
Election 67
Number of candidates: 4
Number of voters: 525
Election 68
Number of candidates: 7
Number of voters: 153
Election 69
Number of candidates: 4
Number of voters: 403
Election 70
Number of candidates: 4
Number of voters: 388
Election 71
Number of candidates: 4
Number of voters: 389
Election 72
Number of candidates: 67
Number of voters: 4
Election 73
Number of candidates: 142
Number of voters: 4
Election 74
Number of candidates: 103
Number of voters: 5
Election 75
Number of candidates: 4
Number of voters: 391
Election 76
Number of candidates: 3
Number of voters: 1591
Election 77
Number of candidates: 3
Number of voters: 3705
Election 78
Number of candidates: 3
Number of voters: 1215
Election 79
Number of candidates: 3
Number of voters: 533
Election 80
Number of candidates: 242
Number of voters: 5
Election 81
Number of candidates: 112
Number of voters: 4
Election 82
Number of candidates: 102
Number of voters: 4
Election 83
Number of candidates: 4
Number of voters: 532
Election 84
Number of candidates: 4
Number of voters: 903
Election 85
Number of candidates: 4
Number of voters: 623
Election 86
Number of candidates: 24
Number of voters: 9
Election 87
Number of candidates: 23
Number of voters: 9
Election 88
Number of candidates: 4
Number of voters: 447
Election 89
Number of candidates: 4
Number of voters: 425
Election 90
Number of candidates: 4
Number of voters: 430
Election 91
Number of candidates: 99
Number of voters: 4
Election 92
Number of candidates: 122
Number of voters: 4
Election 93
Number of candidates: 55
Number of voters: 4
Election 94
Number of candidates: 3
Number of voters: 1022
Election 95
Number of candidates: 3
Number of voters: 664
Election 96
Number of candidates: 3
Number of voters: 375
Election 97
Number of candidates: 3
Number of voters: 423
Election 98
Number of candidates: 3
Number of voters: 379
Election 99
Number of candidates: 240
Number of voters: 5
Election 100
Number of candidates: 68
Number of voters: 4
Election 101
Number of candidates: 96
Number of voters: 4
Election 102
Number of candidates: 115
Number of voters: 4
Election 103
Number of candidates: 6
Number of voters: 15
Election 104
Number of candidates: 4
Number of voters: 485
Election 105
Number of candidates: 4
Number of voters: 420
Election 106
Number of candidates: 4
Number of voters: 350
Election 107
Number of candidates: 23
Number of voters: 9
Election 108
Number of candidates: 19
Number of voters: 9
Election 109
Number of candidates: 4
Number of voters: 355
Election 110
Number of candidates: 4
Number of voters: 512
Election 111
Number of candidates: 4
Number of voters: 473
Election 112
Number of candidates: 115
Number of voters: 4
Election 113
Number of candidates: 67
Number of voters: 4
Election 114
Number of candidates: 87
Number of voters: 4
Election 115
Number of candidates: 3
Number of voters: 833
Election 116
Number of candidates: 3
Number of voters: 1394
Election 117
Number of candidates: 3
Number of voters: 1143
Election 118
Number of candidates: 3
Number of voters: 448
Election 119
Number of candidates: 3
Number of voters: 697
Election 120
Number of candidates: 3
Number of voters: 994
Election 121
Number of candidates: 115
Number of voters: 4
Election 122
Number of candidates: 64
Number of voters: 4
Election 123
Number of candidates: 91
Number of voters: 4
Election 124
Number of candidates: 4
Number of voters: 384
Election 125
Number of candidates: 4
Number of voters: 883
Election 126
Number of candidates: 4
Number of voters: 443
Election 127
Number of candidates: 18
Number of voters: 9
Election 128
Number of candidates: 18
Number of voters: 7
Election 129
Number of candidates: 23
Number of voters: 9
Election 130
Number of candidates: 4
Number of voters: 732
Election 131
Number of candidates: 23
Number of voters: 9
Election 132
Number of candidates: 4
Number of voters: 358
Election 133
Number of candidates: 4
Number of voters: 408
Election 134
Number of candidates: 153
Number of voters: 4
Election 135
Number of candidates: 82
Number of voters: 4
Election 136
Number of candidates: 3
Number of voters: 1860
Election 137
Number of candidates: 3
Number of voters: 617
Election 138
Number of candidates: 3
Number of voters: 529
Election 139
Number of candidates: 3
Number of voters: 940
Election 140
Number of candidates: 95
Number of voters: 4
Election 141
Number of candidates: 128
Number of voters: 4
Election 142
Number of candidates: 4
Number of voters: 448
Election 143
Number of candidates: 4
Number of voters: 446
Election 144
Number of candidates: 18
Number of voters: 7
Election 145
Number of candidates: 4
Number of voters: 525
Election 146
Number of candidates: 18
Number of voters: 9
Election 147
Number of candidates: 4
Number of voters: 418
Election 148
Number of candidates: 4
Number of voters: 392
Election 149
Number of candidates: 14
Number of voters: 9
Election 150
Number of candidates: 4
Number of voters: 554
Election 151
Number of candidates: 4
Number of voters: 362
Election 152
Number of candidates: 70
Number of voters: 4
Election 153
Number of candidates: 240
Number of voters: 5
Election 154
Number of candidates: 3
Number of voters: 542
Election 155
Number of candidates: 3
Number of voters: 501
Election 156
Number of candidates: 3
Number of voters: 467
Election 157
Number of candidates: 3
Number of voters: 360
Election 158
Number of candidates: 4
Number of voters: 795
Election 159
Number of candidates: 242
Number of voters: 4
Election 160
Number of candidates: 127
Number of voters: 4
Election 161
Number of candidates: 4
Number of voters: 803
Election 162
Number of candidates: 4
Number of voters: 391
Election 163
Number of candidates: 20
Number of voters: 9
Election 164
Number of candidates: 4
Number of voters: 731
Election 165
Number of candidates: 4
Number of voters: 657
Election 166
Number of candidates: 4
Number of voters: 440
Election 167
Number of candidates: 4
Number of voters: 382
Election 168
Number of candidates: 11
Number of voters: 30
Election 169
Number of candidates: 23
Number of voters: 9
Election 170
Number of candidates: 4
Number of voters: 352
Election 171
Number of candidates: 4
Number of voters: 547
Election 172
Number of candidates: 4
Number of voters: 797
Election 173
Number of candidates: 4
Number of voters: 405
Election 174
Number of candidates: 106
Number of voters: 4
Election 175
Number of candidates: 240
Number of voters: 4
Election 176
Number of candidates: 69
Number of voters: 4
Election 177
Number of candidates: 4
Number of voters: 800
Election 178
Number of candidates: 3
Number of voters: 1083
Election 179
Number of candidates: 3
Number of voters: 808
Election 180
Number of candidates: 3
Number of voters: 1045
Election 181
Number of candidates: 3
Number of voters: 595
Election 182
Number of candidates: 3
Number of voters: 716
Election 183
Number of candidates: 3
Number of voters: 732
Election 184
Number of candidates: 4
Number of voters: 794
Election 185
Number of candidates: 163
Number of voters: 4
Election 186
Number of candidates: 102
Number of voters: 4
Election 187
Number of candidates: 4
Number of voters: 583
Election 188
Number of candidates: 4
Number of voters: 436
Election 189
Number of candidates: 4
Number of voters: 378
Election 190
Number of candidates: 20
Number of voters: 9
Election 191
Number of candidates: 4
Number of voters: 1814
Election 192
Number of candidates: 4
Number of voters: 578
Election 193
Number of candidates: 4
Number of voters: 417
Election 194
Number of candidates: 4
Number of voters: 823
Election 195
Number of candidates: 4
Number of voters: 793
Election 196
Number of candidates: 4
Number of voters: 454
Election 197
Number of candidates: 4
Number of voters: 486
Election 198
Number of candidates: 4
Number of voters: 394
Election 199
Number of candidates: 242
Number of voters: 5
Election 200
Number of candidates: 71
Number of voters: 4
Election 201
Number of candidates: 93
Number of voters: 4
Election 202
Number of candidates: 3
Number of voters: 2769
Election 203
Number of candidates: 3
Number of voters: 474
Election 204
Number of candidates: 3
Number of voters: 407
Election 205
Number of candidates: 3
Number of voters: 2641
Election 206
Number of candidates: 3
Number of voters: 352
Election 207
Number of candidates: 3
Number of voters: 842
Election 208
Number of candidates: 89
Number of voters: 4
Election 209
Number of candidates: 63
Number of voters: 4
Election 210
Number of candidates: 103
Number of voters: 4
Election 211
Number of candidates: 4
Number of voters: 408
Election 212
Number of candidates: 4
Number of voters: 395
Election 213
Number of candidates: 4
Number of voters: 366
Election 214
Number of candidates: 4
Number of voters: 801
Election 215
Number of candidates: 4
Number of voters: 1207
Election 216
Number of candidates: 14
Number of voters: 9
Election 217
Number of candidates: 19
Number of voters: 9
Election 218
Number of candidates: 4
Number of voters: 858
Election 219
Number of candidates: 4
Number of voters: 510
Election 220
Number of candidates: 4
Number of voters: 795
Election 221
Number of candidates: 4
Number of voters: 712
Election 222
Number of candidates: 4
Number of voters: 449
Election 223
Number of candidates: 93
Number of voters: 4
Election 224
Number of candidates: 110
Number of voters: 4
Election 225
Number of candidates: 3
Number of voters: 737
Election 226
Number of candidates: 3
Number of voters: 351
Election 227
Number of candidates: 3
Number of voters: 416
Election 228
Number of candidates: 3
Number of voters: 727
Election 229
Number of candidates: 10
Number of voters: 5000
Election 230
Number of candidates: 4
Number of voters: 794
Election 231
Number of candidates: 103
Number of voters: 5
Election 232
Number of candidates: 100
Number of voters: 4
Election 233
Number of candidates: 4
Number of voters: 400
Election 234
Number of candidates: 4
Number of voters: 380
Election 235
Number of candidates: 4
Number of voters: 795
Election 236
Number of candidates: 4
Number of voters: 412
Election 237
Number of candidates: 4
Number of voters: 535
Election 238
Number of candidates: 24
Number of voters: 9
Election 239
Number of candidates: 4
Number of voters: 357
Election 240
Number of candidates: 4
Number of voters: 674
Election 241
Number of candidates: 4
Number of voters: 384
Election 242
Number of candidates: 38
Number of voters: 4
Election 243
Number of candidates: 42
Number of voters: 4
Election 244
Number of candidates: 41
Number of voters: 4
Election 245
Number of candidates: 3
Number of voters: 460
Election 246
Number of candidates: 3
Number of voters: 1216
Election 247
Number of candidates: 3
Number of voters: 2310
Election 248
Number of candidates: 3
Number of voters: 815
Election 249
Number of candidates: 3
Number of voters: 1021
Election 250
Number of candidates: 3
Number of voters: 445
Election 251
Number of candidates: 3
Number of voters: 622
Election 252
Number of candidates: 3
Number of voters: 806
Election 253
Number of candidates: 3
Number of voters: 371
Election 254
Number of candidates: 3
Number of voters: 751
Election 255
Number of candidates: 72
Number of voters: 4
Election 256
Number of candidates: 20
Number of voters: 4
Election 257
Number of candidates: 10
Number of voters: 4
Election 258
Number of candidates: 4
Number of voters: 419
Election 259
Number of candidates: 4
Number of voters: 472
Election 260
Number of candidates: 4
Number of voters: 447
Election 261
Number of candidates: 4
Number of voters: 376
Election 262
Number of candidates: 4
Number of voters: 373
Election 263
Number of candidates: 37
Number of voters: 4
Election 264
Number of candidates: 44
Number of voters: 4
Election 265
Number of candidates: 3
Number of voters: 713
Election 266
Number of candidates: 3
Number of voters: 996
Election 267
Number of candidates: 3
Number of voters: 998
Election 268
Number of candidates: 3
Number of voters: 10347
Election 269
Number of candidates: 3
Number of voters: 369
Election 270
Number of candidates: 3
Number of voters: 14081
Election 271
Number of candidates: 3
Number of voters: 1688
Election 272
Number of candidates: 3
Number of voters: 1074
Election 273
Number of candidates: 56
Number of voters: 4
Election 274
Number of candidates: 29
Number of voters: 4
Election 275
Number of candidates: 4
Number of voters: 403
Election 276
Number of candidates: 4
Number of voters: 529
Election 277
Number of candidates: 4
Number of voters: 379
Election 278
Number of candidates: 4
Number of voters: 363
Election 279
Number of candidates: 30
Number of voters: 4
Election 280
Number of candidates: 36
Number of voters: 4
Election 281
Number of candidates: 3
Number of voters: 2708
Election 282
Number of candidates: 3
Number of voters: 860
Election 283
Number of candidates: 3
Number of voters: 2840
Election 284
Number of candidates: 3
Number of voters: 427
Election 285
Number of candidates: 3
Number of voters: 1034
Election 286
Number of candidates: 3
Number of voters: 871
Election 287
Number of candidates: 3
Number of voters: 538
Election 288
Number of candidates: 3
Number of voters: 506
Election 289
Number of candidates: 17
Number of voters: 4
Election 290
Number of candidates: 52
Number of voters: 4
Election 291
Number of candidates: 4
Number of voters: 525
Election 292
Number of candidates: 4
Number of voters: 379
Election 293
Number of candidates: 24
Number of voters: 9
Election 294
Number of candidates: 4
Number of voters: 389
Election 295
Number of candidates: 4
Number of voters: 420
Election 296
Number of candidates: 4
Number of voters: 440
Election 297
Number of candidates: 67
Number of voters: 4
Election 298
Number of candidates: 43
Number of voters: 4
Election 299
Number of candidates: 21
Number of voters: 4
Election 300
Number of candidates: 3
Number of voters: 426
Election 301
Number of candidates: 3
Number of voters: 1631
Election 302
Number of candidates: 3
Number of voters: 443
Election 303
Number of candidates: 3
Number of voters: 578
Election 304
Number of candidates: 3
Number of voters: 453
Election 305
Number of candidates: 3
Number of voters: 391
Election 306
Number of candidates: 3
Number of voters: 417
Election 307
Number of candidates: 3
Number of voters: 955
Election 308
Number of candidates: 3
Number of voters: 2415
Election 309
Number of candidates: 3
Number of voters: 554
Election 310
Number of candidates: 55
Number of voters: 4
Election 311
Number of candidates: 40
Number of voters: 4
Election 312
Number of candidates: 17
Number of voters: 4
Election 313
Number of candidates: 4
Number of voters: 506
Election 314
Number of candidates: 4
Number of voters: 412
Election 315
Number of candidates: 4
Number of voters: 1187
Out of 315 elections:
89.52% have a Condorcet winner
15.24% have a cycle in the majority graph