import logging
import numpy as np
import prefsampling.approval as pref_approval
import prefsampling.ordinal as pref_ordinal
import mapof.elections.cultures.prefsampling_mask as mask
import mapof.elections.cultures.compass as compass
import mapof.elections.cultures.mallows as mallows
import mapof.elections.cultures.matrices.single_crossing_matrices as sc_matrices
import mapof.elections.cultures.matrices.single_peaked_matrices as sp_matrices
import mapof.elections.cultures.pseudo_cultures as pseudo
from mapof.elections.cultures.alliances import (
generate_ordinal_alliance_ic_votes,
generate_ordinal_alliance_urn_votes,
generate_ordinal_alliance_euclidean_votes,
generate_ordinal_alliance_allied_euclidean_votes,
generate_ordinal_alliance_norm_mallows_votes,
)
from mapof.elections.other.glossary import is_pseudo_culture
registered_approval_cultures = {
'identity': mask.identity_approval_mask,
'id': mask.identity_approval_mask, # deprecated name
'ic': mask.impartial_approval_mask, # deprecated name
'impartial': mask.impartial_approval_mask,
'impartial_culture': mask.impartial_approval_mask, # deprecated name
'resampling': pref_approval.resampling,
'disjoint_resampling': pref_approval.disjoint_resampling,
'moving_resampling': pref_approval.moving_resampling,
'noise': pref_approval.noise,
'euclidean': mask.euclidean_approval_mask,
'full': pref_approval.full,
'empty': pref_approval.empty,
'approval_full': pref_approval.full, # deprecated name
'approval_empty': pref_approval.empty, # deprecated name
'truncated_urn': mask.truncated_urn_mask,
'urn_partylist': pref_approval.urn_partylist,
# 'truncated_mallows': mallows.generate_approval_truncated_mallows_votes, # unsupported culture
}
registered_ordinal_cultures = {
'identity': pref_ordinal.identity,
'id': pref_ordinal.identity, # deprecated name
'ic': pref_ordinal.impartial, # deprecated name
'impartial': pref_ordinal.impartial,
'impartial_culture': pref_ordinal.impartial,
'iac': pref_ordinal.impartial_anonymous,
'antagonism': compass.generate_antagonism_votes,
'an': compass.generate_antagonism_votes, # deprecated name
'didi': pref_ordinal.didi,
'plackett-luce': pref_ordinal.plackett_luce,
'urn': pref_ordinal.urn,
'single-crossing': pref_ordinal.single_crossing,
'single-peaked_conitzer': pref_ordinal.single_peaked_conitzer,
'single-peaked_walsh': pref_ordinal.single_peaked_walsh,
'spoc': pref_ordinal.single_peaked_circle,
'un_from_matrix': compass.generate_approx_uniformity_votes, # deprecated name
'approx_uniformity': compass.generate_approx_uniformity_votes,
'approx_stratification': compass.generate_approx_stratification_votes,
'euclidean': mask.euclidean_ordinal_mask,
'group-separable': mask.group_separable_mask,
'mallows': pref_ordinal.mallows,
'norm-mallows': mask.norm_mallows_mask,
'idan_part': compass.generate_idan_part_votes,
'idun_part': compass.generate_idun_part_votes,
'idst_part': compass.generate_idst_part_votes,
'anun_part': compass.generate_anun_part_votes,
'anst_part': compass.generate_anst_part_votes,
'unst_part': compass.generate_unst_part_votes,
'idst_blocks': compass.generate_idst_blocks_votes, # unsupported culture
'unst_topsize': compass.generate_unst_topsize_votes, # unsupported culture
'un_from_list': compass.generate_un_from_list, # unsupported culture
'norm-mallows_mixture': mallows.generate_norm_mallows_mixture_votes, # unsupported culture
}
registered_pseudo_ordinal_cultures = {
'pseudo_uniformity': pseudo.pseudo_uniformity,
'pseudo_stratification': pseudo.pseudo_stratification,
'pseudo_identity': pseudo.pseudo_identity,
'pseudo_antagonism': pseudo.pseudo_antagonism,
'pseudo_unid': pseudo.pseudo_unid,
'pseudo_anid': pseudo.pseudo_anid,
'pseudo_stid': pseudo.pseudo_stid,
'pseudo_anun': pseudo.pseudo_anun,
'pseudo_stun': pseudo.pseudo_stun,
'pseudo_stan': pseudo.pseudo_stan,
'pseudo_sp_conitzer': sp_matrices.get_conitzer_matrix,
'pseudo_sp_walsh': sp_matrices.get_walsh_matrix,
'pseudo_single-crossing': sc_matrices.get_single_crossing_matrix,
}
[docs]
def generate_approval_votes(
culture_id: str = None,
num_voters: int = None,
num_candidates: int = None,
params: dict = None
) -> list | np.ndarray:
"""
Generates approval votes according to the given culture id.
Parameters
----------
culture_id : str
Name of the culture.
num_voters : int
Number of Voters.
num_candidates : int
Number of Candidates
params : dict
Culture parameters.
"""
if culture_id in registered_approval_cultures:
return registered_approval_cultures.get(culture_id)(num_voters, num_candidates, **params)
else:
logging.warning(f'No such culture id: {culture_id}')
return []
[docs]
def generate_ordinal_votes(
culture_id: str = None,
num_candidates: int = None,
num_voters: int = None,
params: dict = None,
**_kwargs
) -> list | np.ndarray:
"""
Generates approval votes according to the given culture id.
Parameters
----------
culture_id : str
Name of the culture.
num_voters : int
Number of Voters.
num_candidates : int
Number of Candidates
params : dict
Culture parameters.
"""
if culture_id in registered_ordinal_cultures:
votes = registered_ordinal_cultures.get(culture_id)(num_voters=num_voters,
num_candidates=num_candidates,
**params)
elif is_pseudo_culture(culture_id):
votes = [culture_id, num_candidates, num_voters, params]
else:
votes = []
logging.warning(
f'No such culture id: {culture_id} \n'
f'If you are using your own instances then ignore this warning.')
if not is_pseudo_culture(culture_id):
votes = [[int(x) for x in row] for row in votes]
return np.array(votes)
def approval_votes_to_vectors(votes, num_candidates=None, num_voters=None):
vectors = np.zeros([num_candidates, num_candidates])
for vote in votes:
denom_in = len(vote)
denom_out = num_candidates - denom_in
for i in range(num_candidates):
if i in vote:
for j in range(denom_in):
vectors[i][j] += 1 / denom_in / num_voters
else:
for j in range(denom_out):
vectors[i][denom_in + j] += 1 / denom_out / num_voters
return vectors
def from_approval(num_candidates: int = None,
num_voters: int = None,
params: dict = None):
votes = generate_approval_votes(culture_id=params['pseudo_culture_id'],
num_candidates=num_candidates, num_voters=num_voters,
params=params)
return approval_votes_to_vectors(votes, num_candidates=num_candidates, num_voters=num_voters)
LIST_OF_ORDINAL_ALLIANCE_MODELS = {
'ic': generate_ordinal_alliance_ic_votes,
'urn': generate_ordinal_alliance_urn_votes,
'euc': generate_ordinal_alliance_euclidean_votes,
'allied_euc': generate_ordinal_alliance_allied_euclidean_votes,
'norm-mallows': generate_ordinal_alliance_norm_mallows_votes,
}
def generate_ordinal_alliance_votes(culture_id: str = None,
num_candidates: int = None,
num_voters: int = None,
params: dict = None):
if culture_id in LIST_OF_ORDINAL_ALLIANCE_MODELS:
votes, alliances = LIST_OF_ORDINAL_ALLIANCE_MODELS.get(culture_id)(
num_voters=num_voters,
num_candidates=num_candidates,
params=params)
else:
votes = []
alliances = []
logging.warning(f'No such culture id: {culture_id}')
return np.array(votes), alliances
[docs]
def add_approval_culture(name, function):
"""
Adds a new approval culture to the list of available approval cultures.
Parameters
----------
name:
Name of the culture, which will be used as culture id.
function : str
Function that generates the votes.
"""
registered_approval_cultures[name] = function
[docs]
def add_ordinal_culture(name, function):
"""
Adds a new ordinal culture to the list of available ordinal cultures.
Parameters
----------
name:
Name of the culture, which will be used as culture id.
function : str
Function that generates the votes.
"""
registered_ordinal_cultures[name] = function
[docs]
def add_pseudo_ordinal_culture(name, function):
"""
Adds a new ordinal culture to the list of available ordinal cultures.
Parameters
----------
name:
Name of the culture, which will be used as culture id.
function : str
Function that generates the frequency matrix.
"""
registered_pseudo_ordinal_cultures[name] = function
__all__ = [
'generate_approval_votes',
'generate_ordinal_votes',
'generate_ordinal_alliance_votes',
'add_approval_culture',
'add_ordinal_culture',
'add_pseudo_ordinal_culture',
'approval_votes_to_vectors',
'from_approval'
]