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

        :param ballot: the ballot or, more generally, an input that can be interpreted by
            :class:`ConverterBallotGeneral`.
        :param voter: the voter.

        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.

        >>> 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()
 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
示例#3
0
 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)
示例#4
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)
 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:
             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)
    def __setitem__(self, key: int, value: object) -> None:
        """
        Set.

        :param key: an integer.
        :param value: the new ballot or, more generally, an input that is understandable by a
            :class:`ConverterBallotGeneral`.

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

        >>> profile = Profile(['a > b', 'b > a'])
        >>> profile[0] = 'a ~ b'
        >>> print(profile)
        a ~ b
        b > a
        """
        self._ballots[key] = ConverterBallotGeneral()(value)
        self.delete_cache()
 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
    def append(self,
               ballot: object,
               weight: Number = 1,
               voter: object = None) -> None:
        """
        Append a ballot to the profile.

        :param ballot: a ballot or, more generally, an input that can be interpreted by
            :class:`ConverterBallotGeneral`.
        :param weight: the weight of the ballot.
        :param voter: the voter.

        >>> 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) -> 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