Esempio n. 1
0
    def remove(self, ballot: object=None, voter: object=None) -> None:
        """
        Remove a ballot from the profile.

        If only the ballot is specified, remove the first matching ballot in the profile.
        If only the voter is specified, remove the first ballot whose voter matches the given voter.
        If both are specified, remove the first ballot matching both descriptions.

        Parameters
        ----------
        ballot : object
            The ballot or, more generally, an input that can be interpreted by :class:`ConverterBallotGeneral`.
        voter : object
            The voter.

        Examples
        --------
            >>> profile = Profile(['a > b', 'b > a'])
            >>> profile.remove('b > a')
            >>> print(profile)
            a > b
        """
        if ballot is None:
            i = next(i for i, v in enumerate(self.voters) if v == voter)
        elif voter is None:
            i = next(i for i, b in enumerate(self.ballots) if b == ConverterBallotGeneral()(ballot))
        else:
            i = next(i for i, b in enumerate(self.ballots)
                     if b == ConverterBallotGeneral()(ballot) and self.voters[i] == voter)
        del self._ballots[i]
        del self._voters[i]
        del self._weights[i]
        self.delete_cache()
Esempio n. 2
0
    def append(self, ballot: object, weight: Number=1, voter: object=None) -> None:
        """
        Append a ballot to the profile.

        Parameters
        ----------
        ballot : object
            A ballot or, more generally, an input that can be interpreted by :class:`ConverterBallotGeneral`.
        weight : Number
            The weight of the ballot.
        voter : object
            The voter.

        Examples
        --------
            >>> profile = Profile(['a > b'])
            >>> profile.append('b > a')
            >>> print(profile)
            a > b
            b > a
        """
        self._ballots.append(ConverterBallotGeneral()(ballot))
        self._weights.append(convert_number(weight))
        self._voters.append(voter)
        self.delete_cache()
 def __call__(self, x: object, candidates: set = None) -> BallotOrder:
     x = ConverterBallotGeneral()(x, candidates=None)
     if isinstance(x, BallotOrder):
         return x.restrict(candidates=candidates)
     if isinstance(x, BallotVeto):
         return BallotOrder([x.candidates_not_in_b,
                             {x.last()}]).restrict(candidates=candidates)
     if isinstance(x, BallotOneName):
         return BallotOrder([{x.first()}, x.candidates_not_in_b
                             ]).restrict(candidates=candidates)
     raise NotImplementedError
 def __call__(self, x: object, candidates: set = None) -> BallotPlurality:
     x = ConverterBallotGeneral()(x, candidates=None)
     if isinstance(x, BallotPlurality):
         return x.restrict(candidates=candidates,
                           priority=self.plurality_priority)
     if isinstance(x, BallotVeto):
         first = x.first(candidates=candidates, priority=self.veto_priority)
         if candidates is None:
             candidates = x.candidates
         else:
             candidates = x.candidates & candidates
         return BallotPlurality(first, candidates=candidates)
     if isinstance(x, BallotOneName):
         x = BallotPlurality(x.candidate, candidates=x.candidates)
         return x.restrict(candidates=candidates,
                           priority=self.one_name_priority)
     if isinstance(x, BallotOrder):
         x = x.restrict(candidates=candidates)
         return BallotPlurality(x.first(priority=self.order_priority),
                                candidates=x.candidates)
     if isinstance(x, Ballot):
         x = ConverterBallotGeneral()(x, candidates=candidates)
         return BallotPlurality(x.first(), candidates=x.candidates)
Esempio n. 5
0
 def __init__(self, *args, converter: ConverterBallot = None, **kwargs):
     """
     Remark: this `__init__` must always be called at the end of the subclasses' `__init__`.
     """
     # Parameters
     if converter is None:
         converter = ConverterBallotGeneral()
     self.converter = converter
     # Computed variables
     self.profile_original_ = None
     self.profile_converted_ = None
     self.candidates_ = None
     # Optional: load a profile at initialization
     if args or kwargs:
         self(*args, **kwargs)
Esempio n. 6
0
 def __call__(self, x: object, candidates: set = None) -> BallotLevels:
     x = ConverterBallotGeneral()(x, candidates=None)
     if isinstance(x, BallotLevels) and any(
         [level in self.scale.levels for level in x.values()]):
         if all([level in self.scale.levels for level in x.values()]):
             return BallotLevels(x.as_dict, scale=self.scale)
         else:
             # Cf. test_ConverterBallotToLevelsListNonNumeric for an explanation of this edge case.
             logging.warning(
                 'Not all levels of ballot ``%s`` are in the scale.' % x)
     x = ConverterBallotToLevelsRange(
         scale=ScaleRange(low=0, high=len(self.scale.levels) - 1),
         borda_unordered_give_points=self.borda_unordered_give_points)(
             x, candidates=None)
     return BallotLevels({c: self.scale.levels[v]
                          for c, v in x.items()},
                         candidates=x.candidates,
                         scale=self.scale).restrict(candidates=candidates)
Esempio n. 7
0
 def __init__(self, ballots: Union[list, 'Profile'], weights: list = None, voters: list = None):
     converter = ConverterBallotGeneral()
     self._ballots = [converter(b) for b in ballots]
     if weights is None:
         if isinstance(ballots, Profile):
             weights = ballots.weights
         else:
             weights = [1] * len(ballots)
     else:
         weights = [convert_number(w) for w in weights]
     self._weights = weights
     if voters is None:
         if isinstance(ballots, Profile):
             self._voters = ballots.voters
         else:
             self._voters = [None] * len(ballots)
     else:
         self._voters = voters
Esempio n. 8
0
    def __setitem__(self, key: int, value: object) -> None:
        """Set.

        Set the corresponding ballot (it does not change the weight or the voter).

        Parameters
        ----------
        key : int
        value : object
            The new ballot or, more generally, an input that is understandable by a :class:`ConverterBallotGeneral`.

        Examples
        --------
            >>> profile = Profile(['a > b', 'b > a'])
            >>> profile[0] = 'a ~ b'
            >>> print(profile)
            a ~ b
            b > a
        """
        self._ballots[key] = ConverterBallotGeneral()(value)
        self.delete_cache()
Esempio n. 9
0
 def __call__(self, x: object, candidates: set = None) -> BallotLevels:
     x = ConverterBallotGeneral()(x, candidates=None)
     if isinstance(x, BallotVeto):
         if x.candidate is None:
             return BallotLevels(
                 dict(), candidates=x.candidates,
                 scale=self.scale).restrict(candidates=candidates)
         return BallotLevels(
             {
                 c: self.low if c == x.candidate else self.high
                 for c in x.candidates
             },
             candidates=x.candidates,
             scale=self.scale).restrict(candidates=candidates)
     if isinstance(x, BallotOneName):  # Including Plurality
         if x.candidate is None:
             return BallotLevels(
                 dict(), candidates=x.candidates,
                 scale=self.scale).restrict(candidates=candidates)
         return BallotLevels(
             {
                 c: self.high if c == x.candidate else self.low
                 for c in x.candidates
             },
             candidates=x.candidates,
             scale=self.scale).restrict(candidates=candidates)
     if isinstance(x, BallotLevels):
         if not x.scale.is_bounded:
             if all([isinstance(v, numbers.Number) for v in x.values()]):
                 x_min, x_max = min(x.values()), max(x.values())
                 if x_min >= self.low and x_max <= self.high:
                     return BallotLevels(
                         x.as_dict,
                         candidates=x.candidates,
                         scale=ScaleInterval(low=self.low,
                                             high=self.high)).restrict(
                                                 candidates=candidates)
                 else:
                     x = BallotLevels(x.as_dict,
                                      candidates=x.candidates,
                                      scale=ScaleInterval(
                                          low=min(x.values()),
                                          high=max(x.values())))
             else:
                 x = BallotLevels(x.as_dict,
                                  candidates=x.candidates,
                                  scale=ScaleFromSet(set(x.values())))
         try:  # Interpret as a cardinal ballot
             return BallotLevels(
                 {
                     c: self.low + my_division(
                         (self.high - self.low) * (v - x.scale.low),
                         (x.scale.high - x.scale.low))
                     for c, v in x.items()
                 },
                 candidates=x.candidates,
                 scale=self.scale).restrict(candidates=candidates)
         except (TypeError, AttributeError):
             x_scale = x.scale
             if isinstance(x_scale, ScaleFromList):
                 return BallotLevels(
                     {
                         c: self.low + my_division(
                             (self.high - self.low) * x_scale.as_dict[x[c]],
                             (len(x_scale.levels) - 1))
                         for c, v in x.items()
                     },
                     candidates=x.candidates,
                     scale=self.scale).restrict(candidates=candidates)
     if isinstance(x, BallotOrder):
         borda = ScorerBorda(
             ballot=x,
             candidates=x.candidates,
             unordered_give_points=self.borda_unordered_give_points).scores_
         score_max = len(
             x.candidates) - 1 if self.borda_unordered_give_points else len(
                 x.candidates_in_b) - 1
         return BallotLevels(
             {
                 c: self.low + my_division(
                     (self.high - self.low) * borda[c], score_max)
                 for c in x.candidates_in_b
             },
             candidates=x.candidates,
             scale=self.scale).restrict(candidates=candidates)
     raise NotImplementedError