Source code for mapof.roommates.cultures.euclidean

import math

import numpy as np
from numpy import linalg

from mapof.roommates.cultures._utils import convert


[docs] def generate_attributes_votes( num_agents: int = None, dim: int = 2, space: str = 'uniform', **_kwargs) -> list[list[int]]: """ Generate votes based on attributes model. Parameters ---------- num_agents : int Number of agents. dim : int Dimension of the space. space : str Distribution of the agents. _kwargs Returns ------- list[list[int]] Votes """ name = f'{dim}d_{space}' agents_skills = np.array([get_rand(name) for _ in range(num_agents)]) agents_weights = np.array([get_rand(name) for _ in range(num_agents)]) votes = np.zeros([num_agents, num_agents], dtype=int) distances = np.zeros([num_agents, num_agents], dtype=float) ones = np.ones([dim], dtype=float) for v in range(num_agents): for c in range(num_agents): votes[v][c] = c if dim == 1: distances[v][c] = abs(1. - agents_skills[c]) * agents_weights[v] else: distances[v][c] = _weighted_l1(ones, agents_skills[c], agents_weights[v]) votes[v] = [x for _, x in sorted(zip(distances[v], votes[v]))] return convert(votes)
[docs] def generate_euclidean_votes( num_agents: int = None, dim: int = 2, space: str = 'uniform', **_kwargs ) -> list[list[int]]: """ Generate votes based on Euclidean model. Parameters ---------- num_agents : int Number of agents. dim : int Dimension of the space. space : str Distribution of the agents. _kwargs Returns ------- list[list[int]] Votes """ name = f'{dim}d_{space}' agents = np.array([get_rand(name, i=i, num_agents=num_agents) for i in range(num_agents)]) votes = np.zeros([num_agents, num_agents], dtype=int) distances = np.zeros([num_agents, num_agents], dtype=float) for v in range(num_agents): for c in range(num_agents): votes[v][c] = c distances[v][c] = np.linalg.norm(agents[v] - agents[c]) votes[v] = [x for _, x in sorted(zip(distances[v], votes[v]))] return convert(votes)
[docs] def generate_reverse_euclidean_votes( num_agents: int = None, dim: int = 2, space: str = 'uniform', proportion: float = 0.5, **_kwargs ) -> list[list[int]]: """ Generate votes based on expectation model. Parameters ---------- num_agents : int Number of agents. dim : int Dimension of the space. space : str Distribution of the agents. proportion : float Proportion of the agents that will have the reverse order. _kwargs Returns ------- list[list[int]] Votes """ name = f'{dim}d_{space}' agents = np.array([get_rand(name, i=i, num_agents=num_agents) for i in range(num_agents)]) votes = np.zeros([num_agents, num_agents], dtype=int) distances = np.zeros([num_agents, num_agents], dtype=float) for v in range(num_agents): for c in range(num_agents): votes[v][c] = c distances[v][c] = np.linalg.norm(agents[v] - agents[c]) votes[v] = [x for _, x in sorted(zip(distances[v], votes[v]))] p = proportion for i in range(int(num_agents * (1. - p))): tmp = list(votes[i]) tmp.reverse() votes[i] = tmp return convert(votes)
[docs] def generate_expectation_votes( num_agents: int = None, dim: int = 2, space: str = 'uniform', std: float = 0.1, **_kwargs ) -> list[list[int]]: """ Generate votes based on reverse Euclidean model. Parameters ---------- num_agents : int Number of agents. dim : int Dimension of the space. space : str Distribution of the agents. std : float Standard deviation of the agents. _kwargs Returns ------- list[list[int]] Votes """ name = f'{dim}d_{space}' agents_reality = np.array([get_rand(name) for _ in range(num_agents)]) agents_wishes = np.zeros([num_agents, 2]) for v in range(num_agents): # while agents_wishes[v][0] <= 0 or agents_wishes[v][0] >= 1: agents_wishes[v][0] = np.random.normal(agents_reality[v][0], std) # while agents_wishes[v][1] <= 0 or agents_wishes[v][1] >= 1: agents_wishes[v][1] = np.random.normal(agents_reality[v][1], std) votes = np.zeros([num_agents, num_agents], dtype=int) distances = np.zeros([num_agents, num_agents], dtype=float) for v in range(num_agents): for c in range(num_agents): votes[v][c] = c distances[v][c] = np.linalg.norm(agents_reality[c] - agents_wishes[v]) votes[v] = [x for _, x in sorted(zip(distances[v], votes[v]))] return convert(votes)
[docs] def generate_fame_votes( num_agents: int = None, dim: int = 2, space: str = 'uniform', radius: float = 0.1, **_kwargs ) -> list[list[int]]: """ Generate votes based on fame model (also known as radius model). Parameters ---------- num_agents : int Number of agents. dim : int Dimension of the space. space : str Distribution of the agents. radius : float Radius of the agents. _kwargs Returns ------- list[list[int]] Votes """ name = f'{dim}d_{space}' agents = np.array([get_rand(name) for _ in range(num_agents)]) votes = np.zeros([num_agents, num_agents], dtype=int) distances = np.zeros([num_agents, num_agents], dtype=float) rays = np.array([np.random.uniform(0, radius) for _ in range(num_agents)]) for v in range(num_agents): for c in range(num_agents): votes[v][c] = c distances[v][c] = np.linalg.norm(agents[v] - agents[c]) distances[v][c] = distances[v][c] - rays[c] votes[v] = [x for _, x in sorted(zip(distances[v], votes[v]))] return convert(votes)
def generate_mallows_euclidean_votes( num_agents: int = None, dim: int = 2, space='uniform', phi=0.5, **_kwargs ) -> list[list[int]]: name = f'{dim}d_{space}' agents = np.array([get_rand(name, i=i, num_agents=num_agents) for i in range(num_agents)]) votes = np.zeros([num_agents, num_agents], dtype=int) distances = np.zeros([num_agents, num_agents], dtype=float) for v in range(num_agents): for c in range(num_agents): votes[v][c] = c distances[v][c] = np.linalg.norm(agents[v] - agents[c]) votes[v] = [x for _, x in sorted(zip(distances[v], votes[v]))] votes = mallows_votes(votes, phi) return convert(votes) #################################################### ### UPDATE THIS TO MATCH THE RESAMPLING APPROACH ###
[docs] def get_rand(model: str, i: int = 0, num_agents: int = 0) -> list: """ generate random values""" point = [0] if model in {"1d_uniform", "1d_interval"}: return np.random.rand() elif model in {'1d_asymmetric'}: if np.random.rand() < 0.3: return np.random.normal(loc=0.25, scale=0.15, size=1) else: return np.random.normal(loc=0.75, scale=0.15, size=1) elif model in {"1d_gaussian"}: point = np.random.normal(0.5, 0.15) while point > 1 or point < 0: point = np.random.normal(0.5, 0.15) # elif model == "1d_one_sided_triangle": # point = np.random.uniform(0, 1) ** 0.5 # elif model == "1d_full_triangle": # point = np.random.choice( # [np.random.uniform(0, 1) ** 0.5, 2 - np.random.uniform(0, 1) ** 0.5]) # elif model == "1d_two_party": # point = np.random.choice([np.random.uniform(0, 1), np.random.uniform(2, 3)]) elif model in {"2d_disc"}: phi = 2.0 * 180.0 * np.random.random() radius = math.sqrt(np.random.random()) * 0.5 point = [0.5 + radius * math.cos(phi), 0.5 + radius * math.sin(phi)] elif model in {"2d_square", "2d_uniform"}: point = [np.random.random(), np.random.random()] # elif model in {'2d_asymmetric'}: # if np.random.rand() < 0.3: # return np.random.normal(loc=0.25, scale=0.15, size=2) # else: # return np.random.normal(loc=0.75, scale=0.15, size=2) # elif model == "2d_sphere": # alpha = 2 * math.pi * np.random.random() # x = 1. * math.cos(alpha) # y = 1. * math.sin(alpha) # point = [x, y] # elif model in ["2d_gaussian"]: # point = [np.random.normal(0.5, 0.15), np.random.normal(0.5, 0.15)] # while np.linalg.norm(point - np.array([0.5, 0.5])) > 0.5: # point = [np.random.normal(0.5, 0.15), np.random.normal(0.5, 0.15)] # elif model in ["3d_cube", "3d_uniform"]: # point = [np.random.random(), np.random.random(), np.random.random()] # elif model in ["5d_uniform"]: # dim = 5 # point = [np.random.random() for _ in range(dim)] # elif model in ["10d_uniform"]: # dim = 10 # point = [np.random.random() for _ in range(dim)] # elif model in {'3d_asymmetric'}: # if np.random.rand() < 0.3: # return np.random.normal(loc=0.25, scale=0.15, size=3) # else: # return np.random.normal(loc=0.75, scale=0.15, size=3) # elif model in ['3d_gaussian']: # point = [np.random.normal(0.5, 0.15), # np.random.normal(0.5, 0.15), # np.random.normal(0.5, 0.15)] # while np.linalg.norm(point - np.array([0.5, 0.5, 0.5])) > 0.5: # point = [np.random.normal(0.5, 0.15), # np.random.normal(0.5, 0.15), # np.random.normal(0.5, 0.15)] # elif model == "4d_cube": # dim = 4 # point = [np.random.random() for _ in range(dim)] # elif model == "5d_cube": # dim = 5 # point = [np.random.random() for _ in range(dim)] else: print('unknown culture_id', model) point = [0, 0] return point
def _weighted_l1(a1, a2, w): total = 0 for i in range(len(a1)): total += abs(a1[i] - a2[i]) * w[i] return total