Example #1
0
    def _parse(self, b: object) -> None:
        """
        Assign `self._internal_representation`.

        The form of `self._internal_representation` may depend on the subclass. For the mother class `BallotOrder`,
        it is of the form [{'a', 'b'}, {'c'}], meaning a ~ b > c. It is used directly for self.as_weak_order.

        Parameters
        ----------
        b : object
            The ballot in a loose input format (cf. documentation of the class and unit tests).
        """
        if isinstance(b, tuple):
            b = list(b)
        if isinstance(b, list):
            self._internal_representation = [
                NiceSet(s) if isinstance(s, set) else NiceSet({s}) for s in b
            ]
        elif isinstance(b, dict):
            self._internal_representation = [
                NiceSet({k
                         for k in b.keys() if b[k] == v})
                for v in sorted(set(b.values()), reverse=True)
            ]
        elif isinstance(b, str):
            self._internal_representation = parse_weak_order(b)
        else:
            raise TypeError('Cannot interpret as an order: %r.' % b)
 def candidates(self) -> NiceSet:
     if self._input_candidates is None:
         if self.candidate is None:
             logging.debug(
                 'The list of candidates was not explicitly given. Using the empty set instead.'
             )
             return NiceSet()
         else:
             logging.debug(
                 'The list of candidates was not explicitly given. Using singleton {%s} instead.'
                 % self.candidate)
             return NiceSet({self.candidate})
     return NiceSet(self._input_candidates)
Example #3
0
    def eliminated_(self) -> NiceSet:
        """NiceSet: The eliminated candidates.

        This should always be non-empty. It may contain all the candidates (for example, it is always the case
        when there was only one candidate in the election).
        """
        return NiceSet(c for tie_class in self.eliminated_order_ for c in tie_class)
    def candidates_in_b(self) -> NiceSet:
        """NiceSet: The candidate that is explicitly mentioned in the ballot.

        This is a singleton with the only candidate contained in the ballot (or an empty set in case of abstention).

        Examples
        --------
            >>> BallotOneName('a', candidates={'a', 'b', 'c'}).candidates_in_b
            {'a'}
            >>> BallotOneName(None, candidates={'a', 'b', 'c'}).candidates_in_b
            {}
        """
        if self.candidate is None:
            return NiceSet()
        else:
            return NiceSet({self.candidate})
    def candidates_not_in_b(self) -> NiceSet:
        """NiceSet: The candidates that were available at the moment of the vote, but are not explicitly mentioned in
        the ballot.

        Examples
        --------
            >>> BallotOneName('a', candidates={'a', 'b', 'c'}).candidates_not_in_b
            {'b', 'c'}
        """
        return NiceSet(self.candidates - {self.candidate})
Example #6
0
    def candidates_not_in_b(self) -> NiceSet:
        """NiceSet: the candidates that were available at the moment of the vote, but are not explicitly mentioned in
        the ballot.

        Examples
        --------
            >>> BallotOrder('a ~ b > c', candidates={'a', 'b', 'c', 'd', 'e'}).candidates_not_in_b
            {'d', 'e'}
        """
        return NiceSet(self.candidates - self.candidates_in_b)
Example #7
0
    def candidates_in_b(self) -> NiceSet:
        """NiceSet: the candidates that are explicitly mentioned in the ballot.

        Examples
        --------
            >>> BallotOrder('a ~ b > c', candidates={'a', 'b', 'c', 'd', 'e'}).candidates_in_b
            {'a', 'b', 'c'}
        """
        return NiceSet(c for indifference_class in self.as_weak_order
                       for c in indifference_class)
Example #8
0
 def order_(self) -> list:
     """list: Result of the election as a (weak) order over the candidates. It is a list of :class:`NiceSet`. The
     first set contains the candidates that have the best score, the second set contains those with the second best
     score, etc.
     """
     return [
         NiceSet(k for k in self.scores_.keys() if self.scores_[k] == v)
         for v in sorted(set(self.scores_.values()),
                         key=cmp_to_key(self.compare_scores),
                         reverse=True)
     ]
Example #9
0
 def __call__(self, ballots: Union[list, Profile] = None, weights: list = None, voters: list = None,
              candidates: set = None):
     self.profile_original_ = Profile(ballots, weights=weights, voters=voters)
     self.profile_converted_ = Profile([self.converter(b, candidates) for b in self.profile_original_],
                                       weights=self.profile_original_.weights, voters=self.profile_original_.voters)
     if candidates is None:
         candidates = set().union(*[b.candidates for b in self.profile_converted_])
     self.candidates_ = NiceSet(candidates)
     self._check_profile(candidates)
     self.delete_cache()
     return self
Example #10
0
 def restrict(self, candidates: set = None, **kwargs) -> 'BallotLevels':
     if kwargs:
         raise TypeError(
             "restrict() got an unexpected keyword argument %r" %
             list(kwargs.keys())[0])
     if candidates is None:
         return self
     return BallotLevels(
         {k: v
          for k, v in self.as_dict.items() if k in candidates},
         candidates=NiceSet(self.candidates & candidates),
         scale=self.scale)
Example #11
0
 def order_(self) -> list:
     orders = [rule.order_ for rule in self.rules_]
     # rank_tuples[a] will be (rank in order 0, rank in order 1, ...)
     rank_tuples = {c: [] for c in self.candidates_}
     for order in orders:
         for i, tie_class in enumerate(order):
             for c in tie_class:
                 rank_tuples[c].append(i)
     rank_tuples = {k: tuple(v) for k, v in rank_tuples.items()}
     # Now, sort by lexicographic order of "rank tuples"
     return [NiceSet(k for k in rank_tuples.keys() if rank_tuples[k] == v)
             for v in sorted(set(rank_tuples.values()))]
    def restrict(self, candidates: set = None, **kwargs) -> 'BallotOneName':
        """
        Restrict the ballot to less candidates.

        Parameters
        ----------
        candidates : set of candidates
            It can be any set of candidates, not necessarily a subset of ``self.candidates``).
            Default: ``self.candidates``.
        kwargs
            * `priority`: a :class:`Priority`. Default: :attr:`Priority.UNAMBIGUOUS`.

        Returns
        -------
        BallotOneName
            The same ballot, "restricted" to the candidates given.

        Examples
        --------
            >>> BallotOneName('a', candidates={'a', 'b'}).restrict(candidates={'b'})
            BallotOneName('b', candidates={'b'})
            >>> BallotOneName('a', candidates={'a', 'b', 'c'}).restrict(candidates={'b', 'c'},
            ...                                                         priority=Priority.ASCENDING)
            BallotOneName('b', candidates={'b', 'c'})
        """
        # noinspection PyUnresolvedReferences
        priority = kwargs.pop('priority', Priority.UNAMBIGUOUS)
        if kwargs:
            raise TypeError(
                "restrict() got an unexpected keyword argument %r" %
                list(kwargs.keys())[0])
        if candidates is None:
            return self
        if self.candidate in candidates:
            return self.__class__(self.candidate,
                                  NiceSet(self.candidates & candidates))
        return self._restrict(restricted_candidates=NiceSet(self.candidates
                                                            & candidates),
                              priority=priority)
Example #13
0
    def candidates(self) -> NiceSet:
        """NiceSet: the candidates.

        If the set was not explicitly given, the candidates are inferred from the ballot.

        Examples
        --------
            >>> BallotOrder('a ~ b > c', candidates={'a', 'b', 'c', 'd', 'e'}).candidates
            {'a', 'b', 'c', 'd', 'e'}
            >>> BallotOrder('a ~ b > c').candidates
            {'a', 'b', 'c'}
        """
        if self._input_candidates is None:
            return self.candidates_in_b
        return NiceSet(self._input_candidates)
 def eliminated_order_(self):
     if self.k > 0:
         n_wanted = self.k
     else:
         n_wanted = self.rule_.n_candidates_ + self.k
     if n_wanted <= 0 or n_wanted >= self.rule_.n_candidates_:
         return self.rule_.order_
     worst_first = []
     for tie_class in self.rule_.order_[::-1]:
         size_class = len(tie_class)
         if size_class <= n_wanted:
             worst_first.append(tie_class)
             n_wanted -= size_class
             if n_wanted == 0:
                 break
         else:
             worst_first.append(
                 NiceSet(
                     self.rule_.tie_break.sort(tie_class)[-1:-1 -
                                                          n_wanted:-1]))
             break
     return worst_first[::-1]
Example #15
0
 def candidates_in_b(self) -> NiceSet:
     return NiceSet(self.as_dict.keys())
Example #16
0
 def as_weak_order(self) -> list:
     return [
         NiceSet(k for k in self.as_dict.keys() if self.as_dict[k] == v)
         for v in sorted(set(self.as_dict.values()), reverse=True)
     ]
Example #17
0
 def qualified_(self) -> NiceSet:
     """NiceSet: The candidates that are qualified (not eliminated).
     """
     return NiceSet(self.rule_.candidates_ - self.eliminated_)
Example #18
0
 def order_(self) -> list:
     matrix = self.matrix_majority_
     condorcet_winners = {c for c in matrix.candidates_
                          if min({v for (i, j), v in matrix.as_dict_.items() if i == c and j != c}) == 1}
     other_candidates = self.candidates_ - condorcet_winners
     return [NiceSet(tie_class) for tie_class in [condorcet_winners, other_candidates] if tie_class]
Example #19
0
 def order_(self) -> list:
     return [
         NiceSet(k for k in self.scores_.keys() if self.scores_[k] == v)
         for v in sorted(set(self.scores_.values()), reverse=True)
     ]
Example #20
0
 def cotrailers_(self):
     """NiceSet: "Cotrailers". The set of candidates with the worst score.
     """
     return NiceSet(
         {k
          for k, v in self.scores_.items() if v == self.worst_score_})
Example #21
0
 def cowinners_(self):
     """NiceSet: Cowinners. The set of candidates with the best score.
     """
     return NiceSet(
         {k
          for k, v in self.scores_.items() if v == self.best_score_})