Ejemplo n.º 1
0
def test_svd():
    ratings = Ratings(np.array([[.5, .6, .3], [.7, 0, .2], [.2, 1, .8]]))
    embeddings = Embeddings(np.array([[1, 1, 0], [1, 0, 1], [0, 1, 0]]))
    election = SVDMax()(ratings, embeddings)
    election.plot_features("3D", show=False)
    election.plot_features("ternary", show=False)
    with pytest.raises(ValueError):
        election.plot_features("3D", dim=[0, 1], show=False)

    embeddings = Embeddings(np.array(([[1, 1, 2], [0, 1, 1]])))
    SVDMax()(ratings, embeddings)
Ejemplo n.º 2
0
 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)
     self.moving_voter = moving_voter
     self.ratings_ = None
Ejemplo n.º 3
0
 def __call__(self, ratings, embeddings=None, k=None):
     self.ratings = Ratings(ratings)
     if embeddings is None:
         self.embeddings = EmbeddingsFromRatingsIdentity()(self.ratings)
     else:
         self.embeddings = Embeddings(embeddings)
     if k is not None:
         self.k_ = k
     self.delete_cache()
     return self
    def __call__(self, ratings):
        ratings = Ratings(ratings)
        positions = (ratings.T / np.sqrt((ratings**2).sum(axis=1))).T
        n_voters, n_candidates = ratings.shape
        self.n_dim = n_candidates

        u, s, v = np.linalg.svd(positions)

        n_voters, n_candidates = positions.shape
        s = np.sqrt(s)
        s /= s.sum()
        n_v = 0
        for s_e in s:
            if s_e >= max(1 / n_voters, 1 / n_candidates):
                n_v += 1

        embeddings = Embeddings(np.dot(positions, positions.T))
        embeddings.n_sing_val_ = n_v
        return embeddings
Ejemplo n.º 5
0
def test_multi():
    ratings = Ratings(np.array([[.5, .6, .3], [.7, 0, .2], [.2, 1, .8]]))
    embeddings = Embeddings(np.array([[1, 1, 0], [1, 0, 1], [0, 1, 0]]))
    election = IterSVD(k=2)(ratings, embeddings)
    election.plot_weights("3D", show=False)
    election.plot_weights("ternary", show=False)
    with pytest.raises(ValueError):
        election.plot_weights("3D", dim=[0, 1], show=False)

    election.plot_winners("3D", show=False)
Ejemplo n.º 6
0
 def set_profile(self, ratings, embeddings=None):
     if embeddings is not None:
         self.embeddings = Embeddings(embeddings)
     self.ratings = Ratings(ratings)
     global_rule = self.rule(self.ratings, self.embeddings)
     self.winner_ = global_rule.winner_
     self.scores_ = global_rule.scores_
     self.welfare_ = global_rule.welfare_
     self.delete_cache()
     return self
Ejemplo n.º 7
0
    def __call__(self, ratings, embeddings=None):
        """
        Parameters
        ----------
        ratings : Ratings or list or np.ndarray
            The ratings of voters on which we run the election.
        embeddings : Embeddings or list or np.ndarray
            The embeddings of the voters on which we run the election.

        Return
        ------
        ScoringRule
            The object itself
        """
        self.delete_cache()
        self.ratings_ = Ratings(ratings)
        if embeddings is None:
            self.embeddings_ = self.embedder(self.ratings_)
        elif embeddings is not None:
            self.embeddings_ = Embeddings(embeddings)
        return self
Ejemplo n.º 8
0
 def __init__(self, ratings, embeddings, rule=None):
     self.ratings = Ratings(ratings)
     self.embeddings = Embeddings(embeddings)
     self.rule = rule
     if rule is not None:
         global_rule = self.rule(self.ratings, self.embeddings)
         self.winner_ = global_rule.winner_
         self.scores_ = global_rule.scores_
         self.welfare_ = global_rule.welfare_
     else:
         self.winner_ = None
         self.scores_ = None
         self.welfare_ = None
Ejemplo n.º 9
0
    def __call__(self, polarisation=0.0):
        """
        Update the parameter of the parametric embeddings
        and create a new ratings.

        Parameters
        _________
        polarisation : float
            Should be between `0` and `1`.
            If it is equal to `0`, then the
            embeddings are uniformly distributed.
            If it is equal to `1`, then each voter's
            embeddings align to the dimension of its group.

        Return
        ------
        Embeddings
            The embeddings generated

        Examples
        --------
        >>> np.random.seed(42)
        >>> generator = EmbeddingsGeneratorPolarized(100, 3)
        >>> embs = generator(.8)
        >>> embs.voter_embeddings(0)
        array([0.12915167, 0.03595039, 0.99097296])
        """

        if polarisation > 1 or polarisation < 0:
            raise ValueError("Polarisation should be between 0 and 1")

        n = len(self._thetas)
        positions = np.zeros((n, self.n_dim))
        for i in range(n):
            p_1 = np.dot(self._orthogonal_profile[i],
                         self._random_profile[i]) * self._orthogonal_profile[i]
            p_2 = self._random_profile[i] - p_1
            e_2 = normalize(p_2)
            positions[i] = self._orthogonal_profile[i] * np.cos(
                self._thetas[i] *
                (1 - polarisation)) + e_2 * np.sin(self._thetas[i] *
                                                   (1 - polarisation))

        return Embeddings(positions)
Ejemplo n.º 10
0
    def __call__(self, ratings, embeddings=None):
        ratings = Ratings(ratings)
        modified_ratings = np.zeros(ratings.shape)
        for i in range(ratings.n_voters):
            modified_ratings[i] = self.f(ratings.voter_ratings(i))
        self.ratings_ = ratings
        self._modified_ratings = modified_ratings

        if self.embeddings_as_history or embeddings is None:
            embedder = EmbeddingsFromRatingsCorrelation()
            if embeddings is None:
                self.embeddings_ = embedder(self.ratings_)
            else:
                self.embeddings_ = embedder(np.concatenate([embeddings, self.ratings_], axis=1))
        else:
            self.embeddings_ = Embeddings(embeddings)
            self.embeddings_.n_sing_val_ = embeddings.n_sing_val_

        self.n_v = self.embeddings_.n_sing_val_ #embedder.n_sing_val_
        self.delete_cache()

        return self
Ejemplo n.º 11
0
    def _ruleResults(self):
        """
        This function execute the rule and compute
        the winners, their features vectors, and the voters'
        weights at each step.

        Return
        ------
        dict
            A dictionary with 3 elements :
            1) ``winners`` contains the list of winners.
            2) ``vectors`` contains the list of
            candidates features vectors.
            3) ``weights_list`` contains the list of
            voters' weight at each step.
        """
        n_voters = self.ratings.n_voters

        winners = []
        vectors = []
        self.weights = np.ones(n_voters)
        ls_weights = [self.weights]

        for _ in range(self.k_):
            winner_j, vec = self._winner_k(winners)
            vectors.append(vec)
            winners.append(winner_j)

            satisfactions = self._satisfaction(winner_j, vec)

            self._updateWeight(satisfactions)
            ls_weights.append(self.weights)

        return {"winners": winners,
                "vectors": Embeddings(vectors),
                "weights_list": ls_weights}
Ejemplo n.º 12
0
    def set_profile(self, ratings, embeddings=None):
        """
        This function update the ratings of voters
        on which we do the analysis.

        Parameters
        ----------
        ratings : Ratings or np.ndarray
        embeddings : Embeddings

        Return
        ------
        SingleVoterManipulation
            The object itself.
        """
        if embeddings is not None:
            self.embeddings = Embeddings(embeddings)
        self.ratings = Ratings(ratings)
        global_rule = self.rule(self.ratings, self.embeddings)
        self.winner_ = global_rule.winner_
        self.scores_ = global_rule.scores_
        self.welfare_ = global_rule.welfare_
        self.delete_cache()
        return self
Ejemplo n.º 13
0
class ScoringRule(DeleteCacheMixin):
    """
    The general class of functions for scoring rules.
    These rules aggregate the scores of every voter to create
    a ranking of the candidates and select a winner.

    Attributes
    ----------
    ratings_ : Ratings
        The ratings of voters on which we run the election.
    embeddings_ : Embeddings
        The embeddings of the voters on which we run the election.
    embedder: EmbeddingsFromRatings
        If no embeddings are specified in the call, this embedder is use to generate
        the embeddings
    score_components : int
        The number of components in the aggregated
        score of every candidate. If `> 1`, we
        perform a lexical sort to obtain the ranking.

    """
    def __init__(self, score_components=1, embedder=None):
        self.score_components = score_components
        self.ratings_ = None
        self.embeddings_ = None
        if embedder is None:
            embedder = EmbeddingsFromRatingsIdentity()
        self.embedder = embedder

    def __call__(self, ratings, embeddings=None):
        """
        Parameters
        ----------
        ratings : Ratings or list or np.ndarray
            The ratings of voters on which we run the election.
        embeddings : Embeddings or list or np.ndarray
            The embeddings of the voters on which we run the election.

        Return
        ------
        ScoringRule
            The object itself
        """
        self.delete_cache()
        self.ratings_ = Ratings(ratings)
        if embeddings is None:
            self.embeddings_ = self.embedder(self.ratings_)
        elif embeddings is not None:
            self.embeddings_ = Embeddings(embeddings)
        return self

    def _score_(self, candidate):
        """
        Return the aggregated score
        of a given candidate. This should be
        implemented for each scoring rule.

        Parameters
        ----------
        candidate : int
            Index of the candidate for whom we want the score.

        Return
        ------
        float or tuple
            if :attr:`~embedded_voting.ScoringRule._score_components` = 1, return a float,
            otherwise a tuple of length :attr:`~embedded_voting.ScoringRule._score_components`.
        """
        raise NotImplementedError

    @cached_property
    def scores_(self):
        """
        Return the aggregated scores of all candidates.

        Return
        ------
        list
            The scores of all candidates. The score of each
            candidate is a float if :attr:`_score_components` = 1
            and a tuple of length :attr:`_score_components` otherwise.
        """
        return [
            self._score_(candidate)
            for candidate in range(self.ratings_.n_candidates)
        ]

    def score_(self, candidate):
        """
        Return the aggregated score
        of a given candidate. This one is called
        by the user to prevent from calling _score_
        every time.

        Parameters
        ----------
        candidate : int
            Index of the candidate for whom we want the score.

        Return
        ------
        float or tuple
            if :attr:`~embedded_voting.ScoringRule._score_components` = 1, return a float,
            otherwise a tuple of length :attr:`~embedded_voting.ScoringRule._score_components`.
        """
        return self.scores_[candidate]

    @cached_property
    def scores_float_(self):
        """
        Return the scores of all candidates,
        but there is only one component for each candidate.

        When :attr:`_score_components` `> 1`,
        we simply take the last components
        if all other components are maximum,
        and `0` otherwise.

        Return
        ------
        float list
            The scores of every candidates.
        """
        if self.score_components == 1:
            return self.scores_
        else:
            max_comp = max(self.scores_)
            return [
                s[-1] if s[:-1] == max_comp[:-1] else 0 for s in self.scores_
            ]

    @cached_property
    def ranking_(self):
        """
        Return the ranking of the candidates
        based on their aggregated scores.

        Return
        ------
        int list
            The ranking of the candidates.
        """

        if self.score_components == 1:
            return list(np.argsort(self.scores_)[::-1])
        else:
            full_scores = [[s[i] for s in self.scores_]
                           for i in range(self.score_components)][::-1]
            return list(np.lexsort(full_scores)[::-1])

    @cached_property
    def winner_(self):
        """
        Return the winner of the election.

        Return
        ------
        int
            The index of the winner of the election.
        """

        return self.ranking_[0]

    @cached_property
    def welfare_(self):
        """
        Return the welfare of all candidates,
        where the welfare is defined as
        `(score - score_min)/(score_max - score_min)`.

        Return
        ------
        float list
            Return the welfare of all candidates.

        """
        scores = self.scores_float_
        max_score = np.max(scores)
        min_score = np.min(scores)
        if max_score == min_score:
            return np.ones(self.ratings_.n_voters)
        return list((scores - min_score) / (max_score - min_score))

    def plot_winner(self,
                    plot_kind="3D",
                    dim=None,
                    fig=None,
                    plot_position=None,
                    show=True):
        """
        Plot the winner of the election.

        Parameters
        ----------
        plot_kind : str
            The kind of plot we want to show.
            Can be ``'3D'`` or ``'ternary'``.
        dim : list
            The 3 dimensions we are using for our plot.
            By default, it is set to ``[0, 1, 2]``.
        fig : matplotlib figure
            The figure on which we add the plot.
        plot_position : list
            The position of the plot on the figure.
            Should be of the form
            ``[n_rows, n_columns, position]``.
        show : bool
            If True, displays the figure
            at the end of the function.

        Return
        ------
        matplotlib ax
            The ax with the plot.

        """
        winner = self.winner_
        ax = self.embeddings_.plot_candidate(self.ratings_,
                                             winner,
                                             plot_kind=plot_kind,
                                             dim=dim,
                                             fig=fig,
                                             plot_position=plot_position,
                                             show=show)
        return ax

    def plot_ranking(self, plot_kind="3D", dim=None, row_size=5, show=True):
        """
        Plot the candidates in the same order than the ranking.

        Parameters
        ----------
        plot_kind : str
            The kind of plot we want to show.
            Can be ``'3D'`` or ``'ternary'``.
        dim : list
            The 3 dimensions we are using for our plot.
            By default, it is set to ``[0, 1, 2]``.
        row_size : int
            Number of subplots by row.
            By default, it is set to 5 by rows.
        show : bool
            If True, displays the figure
            at the end of the function.
        """
        ranking = self.ranking_
        titles = [
            "#%i. Candidate %i" % (i + 1, c) for i, c in enumerate(ranking)
        ]
        self.embeddings_.plot_candidates(self.ratings_,
                                         plot_kind=plot_kind,
                                         dim=dim,
                                         list_candidates=ranking,
                                         list_titles=titles,
                                         row_size=row_size,
                                         show=show)
 def __call__(self, ratings):
     return Embeddings(ratings, norm=True)
 def __call__(self, ratings):
     ratings = Ratings(ratings)
     n_dim = ratings.shape[0]
     return Embeddings(np.eye(n_dim))
 def __call__(self, ratings):
     ratings = Ratings(ratings)
     n_voters = ratings.shape[0]
     embs = np.abs(np.random.randn(n_voters, self.n_dim))
     return Embeddings(embs, norm=True)
Ejemplo n.º 17
0
def test_embeddings():
    emb = Embeddings(np.array([[.2, .5, .3], [.3, .2, .2], [.6, .2, .3]]))
    emb.dilate(approx=False)
    emb.recenter(approx=False)

    emb = Embeddings(np.array([[1, 1, 1], [1, 1, 1]]))
    emb.dilate()

    emb = Embeddings(np.array([[1, 1]]))
    with pytest.raises(ValueError):
        emb.recenter()
    with pytest.raises(ValueError):
        emb.dilate()

    emb = Embeddings(np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]]))
    emb.recenter()
    emb.plot("3D", show=False)
    emb.plot("ternary", dim=[1, 2, 0], show=False)
    with pytest.raises(ValueError):
        emb.plot("test", show=False)
    with pytest.raises(ValueError):
        emb.plot("3D", dim=[1, 2], show=False)

    ratings = np.array([[1, .8, .5], [.6, .5, .2], [.6, .9, .5]])
    emb.plot_candidate(ratings, 0, "3D", show=False)
    emb.plot_candidate(ratings, 0, "ternary", dim=[1, 2, 0], show=False)
    with pytest.raises(ValueError):
        emb.plot_candidate(ratings, 0, "test", show=False)

    emb.plot_candidates(Ratings(ratings), "3D", show=False)
    emb.plot_candidates(ratings,
                        "ternary",
                        show=False,
                        list_titles=["c_1", "c_2", "c_3"])
    with pytest.raises(ValueError):
        emb.plot_candidates(ratings, "test", show=False)

    Embeddings(np.array([[0, -1], [-1, 0]])).recenter()
Ejemplo n.º 18
0
 def __call__(self, *args):
     embs = np.abs(np.random.randn(self.n_voters, self.n_dim))
     return Embeddings(embs, norm=True)