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
end
select (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)
true
In 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())
false
The result above indicates that there are some cases in which the Borda count system violates IIA.