Spatial Model Example
The following example illustrates how to generate simulated preference profiles from a spatial model and evaluate whether the Borda count voting system satisfies independence of irrelevant alternatives (IIA). A spatial model describes the beliefs of voters as points in an n-dimensional space where each dimension represents a belief about a policy or value. Candidates are represented as points in the n-dimensional space. The model assumes voters rank order candidates as an increasing function of distance, where the minimum distance is ranked 1, the second shortest distances is ranked 2 and so forth.
Load Dependencies
The first step is to load the required dependencies.
using LinearAlgebra
using Plots
using RankChoiceVoting
using Random
using StatsBase
Random.seed!(54)Random.TaskLocalRNG()Define Helper Functions
In the code block below, we define two helper functions. The function rank_candidates computes the distance between a voter and the candidatess and returns a rank ordering based on distance. The function select returns the index associated with the most preferred candidate.
function rank_candidates(beliefs, candidates)
return competerank(map(c -> norm(beliefs .- c), candidates))
end
function select(beliefs, candidates)
_,choice = findmin(rank_candidates(beliefs, candidates))
return choice
endselect (generic function with 1 method)Define Candidates
Lets assume the belief space defined over $[0,1]^2$ and the candidates occupy the following positions in that space.
candidates = [(.3,.3), (.3,.5),(.8,.5)]3-element Vector{Tuple{Float64, Float64}}:
(0.3, 0.3)
(0.3, 0.5)
(0.8, 0.5)The plot below illustrates the area of the belief space to which the canidates appeal. For example, voters in the top left quadrant will vote for candidate 2.
points = [Tuple(rand(2)) for _ ∈ 1:10_000]
first_choices = map(x -> select(x, candidates), points)
scatter(points, lims=(0,1), grid=false, legendtitle="candidates", group=first_choices, legend=:outerright)Define Voters
Next, we will define a set of 100 voters by sampling uniformly over $[0,1]^2$:
voters = [Tuple(rand(2)) for _ ∈ 1:100]
votes = map(v -> rank_candidates(v, candidates), voters)
ranks = Ranks(votes)Ranks
┌────────┬───────────┐
│ Counts │ Ranks │
├────────┼───────────┤
│ 32 │ [3, 2, 1] │
│ 15 │ [2, 3, 1] │
│ 19 │ [1, 2, 3] │
│ 26 │ [2, 1, 3] │
│ 7 │ [3, 1, 2] │
│ 1 │ [1, 3, 2] │
└────────┴───────────┘
Evaluate
The last code blocks tests whether the Borda count system satisisfies IIA for the simulated preference profile.
satisfies(Borda(), IIA(), ranks)trueIn this case, it does satisfy IIA. Does hold in general? Let's call satisfies without the preference profile to answer that question.
satisfies(Borda(), IIA())falseThe result above indicates that there are some cases in which the Borda count system violates IIA.