Source code for mapof.core.features.mallows
import logging
import numpy as np
[docs]
def generate_mallows_votes(num_voters, num_candidates, phi=0.5, weight=0, **kwargs):
"""
Generates num_voters votes from Mallows culture_id
with num_candidates candidates and dispersion parameter phi
"""
if phi is None:
logging.warning('phi is not defined')
insertion_probabilites_list = []
for i in range(1, num_candidates):
insertion_probabilites_list.append(computeInsertionProbas(i, phi))
V = []
for i in range(num_voters):
vote = mallowsVote(num_candidates, insertion_probabilites_list)
if weight > 0:
probability = np.random.random()
if probability <= weight:
vote.reverse()
V += [vote]
return V
def computeInsertionProbas(i, phi):
probas = (i + 1) * [0]
for j in range(i + 1):
probas[j] = pow(phi, (i + 1) - (j + 1))
return probas
def weighted_choice(choices):
total = 0
for w in choices:
total = total + w
r = np.random.uniform(0, total)
upto = 0.0
for i, w in enumerate(choices):
if upto + w >= r:
return i
upto = upto + w
assert False, "Shouldn'process_id get here"
def mallowsVote(m, insertion_probabilites_list):
vote = [0]
for i in range(1, m):
index = weighted_choice(insertion_probabilites_list[i - 1])
vote.insert(index, i)
return vote
# Given the number m of candidates and a phi\in [0,1] function computes the expected number of swaps
# in a vote sampled from Mallows culture_id
def calculateExpectedNumberSwaps(num_candidates, phi):
res = phi * num_candidates / (1 - phi)
for j in range(1, num_candidates + 1):
res = res + (j * (phi ** j)) / ((phi ** j) - 1)
return res
# Given the number m of candidates and a absolute number of expected swaps exp_abs, this function
# returns a value of phi such that in a vote sampled from Mallows culture_id with this parameter
# the expected number of swaps is exp_abs
def phi_from_normphi(num_candidates=10, normphi=None):
if normphi is None:
logging.warning('normphi is not defined')
return -1
if normphi == 1:
return 1
if normphi > 2 or normphi < 0:
logging.warning("Incorrect normphi value")
if normphi > 1:
return 2 - normphi
exp_abs = normphi * (num_candidates * (num_candidates - 1)) / 4
low = 0
high = 1
while low <= high:
mid = (high + low) / 2
cur = calculateExpectedNumberSwaps(num_candidates, mid)
if abs(cur - exp_abs) < 1e-5:
return mid
# If x is greater, ignore left half
if cur < exp_abs:
low = mid
# If x is smaller, ignore right half
elif cur > exp_abs:
high = mid
# If we reach here, then the element was not present
return -1
def mallows_vote(vote, phi):
num_candidates = len(vote)
raw_vote = generate_mallows_votes(1, num_candidates, phi)[0]
new_vote = [0] * len(vote)
for i in range(num_candidates):
new_vote[raw_vote[i]] = vote[i]
return new_vote
def mallows_votes(votes, phi):
for i in range(len(votes)):
votes[i] = mallows_vote(votes[i], phi)
return votes