Source code for embedded_voting.experiments.moving_voter

# -*- coding: utf-8 -*-
"""
This file is part of Embedded Voting.
"""

import numpy as np
import matplotlib.pyplot as plt

from embedded_voting.ratings.ratings import Ratings
from embedded_voting.utils.miscellaneous import normalize
from embedded_voting.utils.plots import create_3d_plot, create_ternary_plot
from embedded_voting.rules.singlewinner_rules.rule_sum_ratings import RuleSumRatings
from embedded_voting.rules.singlewinner_rules.rule_svd_max import RuleSVDMax
from embedded_voting.rules.singlewinner_rules.rule_svd_nash import RuleSVDNash
from embedded_voting.embeddings.embeddings import Embeddings


[docs]class MovingVoter: """ This subclass of `Embeddings` can be used to see what happen to the scores of the different candidates when a voter moves from a group to another. There is 4 candidates and 3 groups: Each group strongly support one of the candidate and dislike the other candidates, except the last candidate which is fine for every group. The moving voter is a voter that do not have any preference between the candidates (she gives a score of `0.8` to every candidate, except `0.5` for the last one), but her embeddings move from one position to another. Parameters ---------- embeddings: Embeddings The embeddings of the voters. If none is specified, embeddings are the identity matrix. moving_voter: int The index of the voter that is moving Attributes ---------- rule: Rule The rule we are using in the election. moving_voter: int The index of the voter that is moving. ratings_: np.ndarray The ratings given by the voters to the candidates Examples -------- >>> moving_profile = MovingVoter() >>> moving_profile(RuleSumRatings()) # DOCTEST: +ELLIPSIS <embedded_voting.experiments.moving_voter.MovingVoter object at ...> >>> moving_profile.moving_voter 0 >>> moving_profile.embeddings Embeddings([[1., 0., 0.], [0., 0., 1.], [0., 1., 0.], [1., 0., 0.]]) >>> moving_profile.ratings_ Ratings([[0.8, 0.8, 0.8, 0.5], [0.1, 0.1, 1. , 0.5], [0.1, 1. , 0.1, 0.5], [1. , 0.1, 0.1, 0.5]]) """ def __init__(self, embeddings=None, moving_voter=0): self.rule = None if embeddings is None: embeddings = np.array([[1., 0., 0.], [0., 0., 1.], [0., 1., 0.], [1., 0., 0.]]) self.embeddings = Embeddings(embeddings, norm=True) self.moving_voter = moving_voter self.ratings_ = None def __call__(self, rule, ratings=None): """ This function is used to update the rule used, and also the ratings Parameters ---------- rule: Rule The rule we will use ratings: np.ndarray or Ratings The ratings of the candidates Return ------ MovingVoter The object """ self.rule = rule if ratings is None: ratings = np.array([[.8, .8, .8, .5], [.1, .1, 1, .5], [.1, 1, .1, .5], [1, .1, .1, .5]]) self.ratings_ = Ratings(ratings) return self
[docs] def plot_scores_evolution(self, show=True): """ This function plot the evolution of the scores of the candidates when the moving voters' embeddings are changing. Parameters ---------- show : bool If True, displays the figure at the end of the function. Examples -------- >>> p = MovingVoter()(RuleSVDNash()) >>> p.plot_scores_evolution(show=False) """ tab_x = np.linspace(0, 1, 50) tab_y = [] for x in tab_x: self.embeddings[self.moving_voter] = normalize([1-x, x, 0]) tab_y.append(self.rule(self.ratings_, self.embeddings).scores_focus_on_last_) tab_y = np.array(tab_y).T name = ["Start", "End", "Orthogonal", "Consensus"] for i in range(self.ratings_.n_candidates): plt.plot(tab_x, tab_y[i], label=name[i]) plt.title("Evolution of the score") plt.xlabel("X coordinate of moving voter") plt.ylabel("Score") plt.xlim(0, 1) plt.legend() if show: plt.show() # pragma: no cover
[docs] def plot_features_evolution(self, show=True): """ This function plot the evolution of the features of the candidates when the moving voters' embeddings are changing. Only works for :class:`RuleSVDMax` and :class:`RuleFeatures`. Parameters ---------- show : bool If True, displays the figure at the end of the function. Examples -------- >>> p = MovingVoter()(RuleSVDMax()) >>> p.plot_features_evolution(show=False) """ tab_x = np.linspace(0, 1, 20) tab_y = [] for x in tab_x: self.embeddings[self.moving_voter] = normalize([1-x, x, 0]) tab_y.append(self.rule(self.ratings_, self.embeddings).features_) tab_y = np.array(tab_y) fig = plt.figure(figsize=(10, 5)) ax = create_3d_plot(fig, position=[1, 2, 1]) name = ["Start", "End", "Orthogonal", "Consensus"] for i in range(self.ratings_.n_candidates): vec_init = normalize(tab_y[0, i])**2 ax.plot(tab_y[::, i, 0], tab_y[::, i, 1], tab_y[::, i, 2], color=(vec_init[0] * 0.8, vec_init[1] * 0.8, vec_init[2] * 0.8), alpha=0.5, label=name[i]) for j, v in enumerate(tab_y[::, i]): vec_normalized = normalize(v) ax.plot([0, v[0]], [0, v[1]], [0, v[2]], color=(vec_normalized[0] * 0.8, vec_normalized[1] * 0.8, vec_normalized[2] * 0.8), alpha=j / 60) ax.set_title("Evolution of the features") plt.legend() tax = create_ternary_plot(fig, position=[1, 2, 2]) for i in range(self.ratings_.n_candidates): points = [normalize(x[[0, 2, 1]])**2 for x in tab_y[::, i]] vec_init = normalize(tab_y[0, i, [0, 2, 1]])**2 tax.plot(points, color=(vec_init[0] * 0.8, vec_init[2] * 0.8, vec_init[1] * 0.8), alpha=0.8) tax.scatter([vec_init], color=(vec_init[0] * 0.8, vec_init[2] * 0.8, vec_init[1] * 0.8), alpha=0.7, s=50) if show: plt.show() # pragma: no cover