Skip to content

Commit

Permalink
approval validation
Browse files Browse the repository at this point in the history
  • Loading branch information
szufix committed Jan 30, 2024
1 parent 1ee65d9 commit 0af82b2
Show file tree
Hide file tree
Showing 15 changed files with 1,196 additions and 867 deletions.
14 changes: 9 additions & 5 deletions prefsampling/filters/approval_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ def permute_approval_voters(votes: list[set[int]], seed: int = None) -> list[set


def rename_approval_candidates(
votes: list[set[int]], seed: int = None
votes: list[set[int]],
seed: int = None,
num_candidates: int = None
) -> list[set[int]]:
"""
Renames the candidates in approval votes.
Expand All @@ -36,18 +38,20 @@ def rename_approval_candidates(
Approval votes.
seed : int
Seed for numpy random number generator.
num_candidates : int
Number of Candidates.
Returns
-------
list[set[int]]
Approval votes.
"""
rng = np.random.default_rng(seed)
max_id = max([max(vote) for vote in votes if len(vote) > 0])
mapping = rng.permutation(max_id + 1)

rng = np.random.default_rng(seed)
if num_candidates is None:
num_candidates = max([max(vote) for vote in votes if len(vote) > 0]) + 1
mapping = rng.permutation(num_candidates)
votes = [{mapping[c] for c in vote} for vote in votes]

return votes


Expand Down
6 changes: 3 additions & 3 deletions prefsampling/ordinal/singlecrossing.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ def single_crossing(
votes[i, :] = domain[index]
last_sampled_index = index

# vote_indices = np.sort(rng.choice(np.arange(domain_size), size=num_voters))
# for i, index in enumerate(vote_indices):
# votes[i, :] = domain[index]
vote_indices = np.sort(rng.choice(np.arange(domain_size), size=num_voters))
for i, index in enumerate(vote_indices):
votes[i, :] = domain[index]
return votes


Expand Down
2 changes: 2 additions & 0 deletions prefsampling/tree/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
"schroeder_tree_lescanne",
"schroeder_tree_brute_force",
"all_schroeder_tree",
"caterpillar_tree",
"caterpillar_tree",
]
Empty file added validation/approval/__init__.py
Empty file.
64 changes: 64 additions & 0 deletions validation/approval/euclidean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from prefsampling.core.euclidean import EuclideanSpace
from prefsampling.ordinal import euclidean
from validation.utils import get_all_subsets
from validation.validator import Validator


class ApprovalEuclideanValidatorUniform(Validator):
def __init__(self):
parameters_list = []
for space in EuclideanSpace:
for dimension in [2, 3]:
parameters_list.append(
{
"num_voters": 50,
"num_candidates": 5,
"space": space,
"dimension": dimension,
},
)
super(ApprovalEuclideanValidatorUniform, self).__init__(
parameters_list,
"Euclidean",
"euclidean_uniform",
True,
sampler_func=euclidean,
constant_parameters=("num_voters", "num_candidates"),
faceted_parameters=("space", "dimension"),
)

def sample_cast(self, sample):
return tuple(sample[0])

def all_outcomes(self, sampler_parameters):
return get_all_ranks(sampler_parameters["num_candidates"])

def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:
return {o: 1 / len(all_outcomes) for o in all_outcomes}


class OrdinalEuclideanValidator(Validator):
def __init__(self):
parameters_list = []
for space in EuclideanSpace:
for dimension in [2, 3]:
parameters_list.append(
{
"num_voters": 3,
"num_candidates": 3,
"space": space,
"dimension": dimension,
},
)
super(OrdinalEuclideanValidator, self).__init__(
parameters_list,
"Euclidean",
"euclidean",
False,
sampler_func=euclidean,
constant_parameters=("num_voters", "num_candidates"),
faceted_parameters=("space", "dimension"),
)

def sample_cast(self, sample):
return tuple(tuple(r) for r in sample)
30 changes: 30 additions & 0 deletions validation/approval/identity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from prefsampling.approval import identity
from validation.utils import get_all_subsets
from validation.validator import Validator


class ApprovalIdentityValidator(Validator):
def __init__(self):
parameters_list = [
{"num_voters": 1, "num_candidates": 4, "p": 0.25},
{"num_voters": 1, "num_candidates": 4, "p": 0.5},
]
super(ApprovalIdentityValidator, self).__init__(
parameters_list,
"Identity",
"identity",
True,
sampler_func=identity,
constant_parameters=("num_voters", "num_candidates"),
faceted_parameters="p",
)

def all_outcomes(self, sampler_parameters):
return get_all_subsets(sampler_parameters["num_candidates"])

def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:
k = int(sampler_parameters["p"] * sampler_parameters["num_candidates"])
return {str(k): 1}

def sample_cast(self, sample):
return str(len(sample[0]))
44 changes: 44 additions & 0 deletions validation/approval/impartial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from prefsampling.approval import impartial
from validation.utils import get_all_subsets
from validation.validator import Validator
from math import factorial


class ApprovalImpartialValidator(Validator):
def __init__(self):
parameters_list = [
{"num_voters": 1, "num_candidates": 4, "p": 0.3},
{"num_voters": 1, "num_candidates": 4, "p": 0.5},
{"num_voters": 1, "num_candidates": 4, "p": 0.7},
{"num_voters": 1, "num_candidates": 5, "p": 0.3},
{"num_voters": 1, "num_candidates": 5, "p": 0.5},
{"num_voters": 1, "num_candidates": 5, "p": 0.7},
]
super(ApprovalImpartialValidator, self).__init__(
parameters_list,
"Impartial",
"impartial_apr",
True,
sampler_func=impartial,
constant_parameters="num_voters",
faceted_parameters=("p", "num_candidates"),
)

def all_outcomes(self, sampler_parameters):
return get_all_subsets(sampler_parameters["num_candidates"])

def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:

m = sampler_parameters["num_candidates"]
p = sampler_parameters["p"]

probabilities = [None for _ in range(m+1)]
for k in range(m+1):
binomial_coefficient = factorial(m) / (factorial(k) * factorial(m - k))
probability = binomial_coefficient * (p ** k) * ((1 - p) ** (m - k))
probabilities[k] = probability

return {str(len(o)): probabilities[len(o)] for o in all_outcomes}

def sample_cast(self, sample):
return str(len(sample[0]))
42 changes: 42 additions & 0 deletions validation/approval/noise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import math

from prefsampling.approval import noise
from validation.utils import get_all_subsets, hamming
from validation.validator import Validator


class ApprovalNoiseValidator(Validator):
def __init__(self):
parameters_list = [
{"num_voters": 1, "num_candidates": 4, "phi": 0.25, "p": 0.25},
{"num_voters": 1, "num_candidates": 4, "phi": 0.25, "p": 0.5},
{"num_voters": 1, "num_candidates": 4, "phi": 0.25, "p": 0.75},
{"num_voters": 1, "num_candidates": 4, "phi": 0.5, "p": 0.25},
{"num_voters": 1, "num_candidates": 4, "phi": 0.5, "p": 0.5},
{"num_voters": 1, "num_candidates": 4, "phi": 0.5, "p": 0.75},
]
super(ApprovalNoiseValidator, self).__init__(
parameters_list,
"Noise",
"noise",
True,
sampler_func=noise,
constant_parameters=("num_voters", "num_candidates"),
faceted_parameters=("phi", "p"),
)

def all_outcomes(self, sampler_parameters):
return get_all_subsets(sampler_parameters["num_candidates"])

def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:
m = sampler_parameters["num_candidates"]
p = sampler_parameters["p"]
phi = sampler_parameters["phi"]
k = math.floor(p*m)
central_vote = {i for i in range(k)}
tmp_dict = {str(o): phi**hamming(central_vote, o) for o in all_outcomes}
denom = sum(tmp_dict.values())
return {str(o): tmp_dict[str(o)]/denom for o in all_outcomes}

def sample_cast(self, sample):
return str(sample[0])
30 changes: 30 additions & 0 deletions validation/approval/partylist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from prefsampling.approval import partylist
# from validation.utils import get_all_ranks, get_all_anonymous_profiles
from validation.validator import Validator


class ApprovalImpartialValidator(Validator):
def __init__(self):
parameters_list = [
{"num_voters": 1, "num_candidates": 4},
{"num_voters": 1, "num_candidates": 5},
{"num_voters": 1, "num_candidates": 6},
]
super(ApprovalImpartialValidator, self).__init__(
parameters_list,
"Partylist",
"partylist",
True,
sampler_func=partylist,
constant_parameters="num_voters",
faceted_parameters="num_candidates",
)

# def all_outcomes(self, sampler_parameters):
# return get_all_ranks(sampler_parameters["num_candidates"])

# def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:
# return {o: 1 / len(all_outcomes) for o in all_outcomes}

# def sample_cast(self, sample):
# return tuple(sample[0])
55 changes: 55 additions & 0 deletions validation/approval/resampling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import math

from prefsampling.approval import resampling
from validation.utils import get_all_subsets
from validation.validator import Validator


class ApprovalResamplingValidator(Validator):
def __init__(self):
parameters_list = [
{"num_voters": 1, "num_candidates": 6, "phi": 0.25, "p": 0.5},
{"num_voters": 1, "num_candidates": 6, "phi": 0.5, "p": 0.5},
{"num_voters": 1, "num_candidates": 6, "phi": 0.75, "p": 0.5},
{"num_voters": 1, "num_candidates": 6, "phi": 0.25, "p": 0.34},
{"num_voters": 1, "num_candidates": 6, "phi": 0.5, "p": 0.34},
{"num_voters": 1, "num_candidates": 6, "phi": 0.75, "p": 0.34},
]
super(ApprovalResamplingValidator, self).__init__(
parameters_list,
"Resampling",
"resampling",
True,
sampler_func=resampling,
constant_parameters=("num_voters", "num_candidates"),
faceted_parameters=("phi", "p"),
)

def all_outcomes(self, sampler_parameters):
return get_all_subsets(sampler_parameters["num_candidates"])

def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:
m = sampler_parameters["num_candidates"]
p = sampler_parameters["p"]
phi = sampler_parameters["phi"]
k = math.floor(p*m)
central_vote = {i for i in range(k)}

A = {}
for outcome in all_outcomes:
prob = 1
for c in range(m):
if c in central_vote and c in outcome:
prob *= (1-phi) + phi*p
elif c in central_vote and c not in outcome:
prob *= phi*(1-p)
elif c not in central_vote and c in outcome:
prob *= phi*p
else:
prob *= (1-phi) + phi*(1-p)
A[str(outcome)] = prob
return A

def sample_cast(self, sample):
return str(sample[0])

30 changes: 30 additions & 0 deletions validation/approval/truncated_urn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from prefsampling.approval import impartial
from validation.utils import get_all_subsets
from validation.validator import Validator


class ApprovalImpartialValidator(Validator):
def __init__(self):
parameters_list = [
{"num_voters": 1, "num_candidates": 4},
{"num_voters": 1, "num_candidates": 5},
{"num_voters": 1, "num_candidates": 6},
]
super(ApprovalImpartialValidator, self).__init__(
parameters_list,
"Impartial",
"impartial",
True,
sampler_func=impartial,
constant_parameters="num_voters",
faceted_parameters="num_candidates",
)

def all_outcomes(self, sampler_parameters):
return get_all_subsets(sampler_parameters["num_candidates"])

# def theoretical_distribution(self, sampler_parameters, all_outcomes) -> dict:
# return {o: 1 / len(all_outcomes) for o in all_outcomes}

# def sample_cast(self, sample):
# return tuple(sample[0])
Loading

0 comments on commit 0af82b2

Please sign in to comment.