Probability Models

To generate profiles, we use the Preflib.org tools available at https://github.com/PrefLib/PrefLib-Tools.

Impartial (Anonymous) Culture

  1. IC: Impartial Culture Model - generate a profile by sampling from a uniform distribution over profiles with \(n\) candidates and \(m\) voters.

  2. IAC: Impartial Anonymous Culture Model - generate a profile by sampling from a uniform distribution over anonymous profiles with \(n\) candidates and \(m\) voters.

  3. 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
../_images/probmodels_21_1.png
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
../_images/probmodels_22_1.png

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