Esempio n. 1
0
    def tau_sincere(self):
        """Tau-vector associated to sincere voting.

        Returns
        -------
        TauVector
            * In Approval, all voters approve of their top candidate, and voters approve of their middle candidate if
              and only if their utility for her is strictly greater than 0.5.
            * In Plurality, all voters vote for their top candidate.
            * In Anti-plurality, all voters vote against their bottom candidate (i.e. for the other two).

        Notes
        -----
        In Plurality and Anti-plurality, sincere and fanatic voting are the same. They differ only in Approval.
        """
        t = self.d_ballot_share_weak_voters_sincere.copy()
        for ranking in RANKINGS:
            if self.voting_rule == APPROVAL:
                share_vote_one_two = self.have_ranking_with_utility_above_u(ranking, Fraction(1, 2))
                share_vote_one = self.d_ranking_share[ranking] - share_vote_one_two
                t[ballot_one(ranking)] += share_vote_one
                t[ballot_one_two(ranking)] += share_vote_one_two
            elif self.voting_rule == PLURALITY:
                t[ballot_one(ranking)] += self.d_ranking_share[ranking]
            elif self.voting_rule == ANTI_PLURALITY:
                t[ballot_one_two(ranking)] += self.d_ranking_share[ranking]
            else:
                raise NotImplementedError
        return TauVector(t, voting_rule=self.voting_rule, symbolic=self.symbolic)
Esempio n. 2
0
    def is_equilibrium(self, strategy):
        """Whether a strategy is an equilibrium.

        Parameters
        ----------
        strategy : StrategyTwelve
            A strategy that specifies at least all the rankings that are present in the profile.

        Returns
        -------
        EquilibriumStatus
            Whether `strategy` is an equilibrium in this profile.

        Examples
        --------
            >>> from fractions import Fraction
            >>> profile = ProfileTwelve({'ab_c': Fraction(1, 10), 'b_ac': Fraction(6, 10),
            ...                          'c_ab': Fraction(2, 10), 'ca_b': Fraction(1, 10)})
            >>> strategy = StrategyTwelve({'abc': 'ab', 'bac': 'b', 'cab': 'utility-dependent'})
            >>> profile.is_equilibrium(strategy)
            EquilibriumStatus.EQUILIBRIUM
        """
        d_ranking_best_response = self.tau(strategy).d_ranking_best_response
        status = EquilibriumStatus.EQUILIBRIUM
        for ranking, share in self.d_ranking_share.items():
            if share == 0:
                continue
            best_response = d_ranking_best_response[ranking]
            if best_response.ballot == INCONCLUSIVE:  # pragma: no cover - Should never happen
                status = min(status, EquilibriumStatus.INCONCLUSIVE)
            else:
                type_1 = ranking[:1] + '_' + ranking[1:]  # E.g. a_bc
                type_12 = ranking[:2] + '_' + ranking[2:]  # E.g. ab_c
                if best_response.ballot == UTILITY_DEPENDENT:
                    if self.voting_rule == APPROVAL:
                        best_ballot_1, best_ballot_12 = ballot_one(
                            ranking), ballot_one_two(ranking)
                    elif self.voting_rule == PLURALITY:
                        best_ballot_1, best_ballot_12 = ballot_one(
                            ranking), ballot_two(ranking)
                    elif self.voting_rule == ANTI_PLURALITY:
                        best_ballot_1, best_ballot_12 = ballot_one_three(
                            ranking), ballot_one_two(ranking)
                    else:
                        raise NotImplementedError
                else:
                    best_ballot_1 = best_response.ballot
                    best_ballot_12 = best_response.ballot
                if self.d_type_share[type_1] > 0 and getattr(
                        strategy, type_1) != best_ballot_1:
                    return EquilibriumStatus.NOT_EQUILIBRIUM
                if self.d_type_share[type_12] > 0 and getattr(
                        strategy, type_12) != best_ballot_12:
                    return EquilibriumStatus.NOT_EQUILIBRIUM
        return status
Esempio n. 3
0
    def share_sincere_among_strategic_voters(self, strategy):
        """Share of strategic voters that happen to cast a sincere ballot.

        Parameters
        ----------
        strategy : StrategyTwelve
            A strategy that specifies at least all the rankings that are present in the profile.

        Returns
        -------
        Number
            The ratio of sincere voters among strategic voters.

        Examples
        --------
            >>> from fractions import Fraction
            >>> profile = ProfileTwelve({'ab_c': Fraction(1, 10), 'b_ac': Fraction(6, 10),
            ...                          'c_ab': Fraction(2, 10), 'ca_b': Fraction(1, 10)})
            >>> strategy = StrategyTwelve({'abc': 'ab', 'bac': 'b', 'cab': 'utility-dependent'})
            >>> profile.share_sincere_among_strategic_voters(strategy)
            1
        """
        assert self.voting_rule == strategy.voting_rule
        # Weak orders: these voters are always "sincere", even in Plurality or Anti-Plurality. For example, in
        # Plurality, a voter a~b>c will either vote for a or b, and this is considered "sincere".
        share_sincere = sum(self.d_weak_order_share.values())
        # Rankings
        for ranking, ballot in strategy.d_ranking_ballot.items():
            if self.d_ranking_share[ranking] == 0:
                continue
            # For a ranking abc, ballot can be real ballots (e.g. 'a', 'ab'), '' or 'utility-dependent'.
            if self.voting_rule == APPROVAL:
                if ballot == ballot_one(ranking):
                    share_sincere += self.have_ranking_with_utility_below_u(
                        ranking, u=.5)
                elif ballot == ballot_one_two(ranking):
                    share_sincere += self.have_ranking_with_utility_above_u(
                        ranking, u=.5)
                else:
                    share_sincere += self.d_ranking_share[ranking]
            elif self.voting_rule == PLURALITY:
                if ballot == ballot_one(ranking):
                    share_sincere += self.d_ranking_share[ranking]
                elif ballot == UTILITY_DEPENDENT:
                    share_sincere += self.have_ranking_with_utility_below_u(
                        ranking, u=.5)
            elif self.voting_rule == ANTI_PLURALITY:
                if ballot == ballot_one_two(ranking):
                    share_sincere += self.d_ranking_share[ranking]
                elif ballot == UTILITY_DEPENDENT:
                    share_sincere += self.have_ranking_with_utility_above_u(
                        ranking, u=.5)
            else:
                raise NotImplementedError
        return self.ce.simplify(share_sincere)
Esempio n. 4
0
 def _f(self):
     if getattr(self, ranking) == UTILITY_DEPENDENT:
         if getattr(self, 'voting_rule') in {APPROVAL, PLURALITY}:
             return ballot_one(ranking)
         elif getattr(self, 'voting_rule') == ANTI_PLURALITY:
             return ballot_one_three(ranking)
         else:
             raise NotImplementedError
     return getattr(self, ranking)
 def __init__(self,
              d,
              d_weak_order_ballot=None,
              ratio_optimistic=None,
              profile=None,
              voting_rule=None):
     voting_rule = self._get_voting_rule_(profile, voting_rule)
     # Prepare the dictionaries of thresholds and ratios
     self.d_ranking_threshold = DictPrintingInOrderIgnoringNone(
         {ranking: None
          for ranking in RANKINGS})
     self.d_ranking_ratio_optimistic = DictPrintingInOrderIgnoringNone(
         {ranking: None
          for ranking in RANKINGS})
     for ranking, value in d.items():
         if isinstance(value, tuple):
             self.d_ranking_threshold[
                 ranking], self.d_ranking_ratio_optimistic[ranking] = value
         else:
             self.d_ranking_threshold[ranking] = value
             self.d_ranking_ratio_optimistic[ranking] = ratio_optimistic
     # Prepare the dictionary of ballots
     d_ranking_ballot = DictPrintingInOrderIgnoringZeros()
     for ranking, threshold in self.d_ranking_threshold.items():
         if threshold is None:
             d_ranking_ballot[ranking] = ''
         elif threshold == 1:
             if voting_rule in {APPROVAL, PLURALITY}:
                 d_ranking_ballot[ranking] = ballot_one(ranking)
             elif voting_rule == ANTI_PLURALITY:
                 d_ranking_ballot[ranking] = ballot_one_three(ranking)
             else:
                 raise NotImplementedError
         elif threshold == 0:
             if voting_rule in {APPROVAL, ANTI_PLURALITY}:
                 d_ranking_ballot[ranking] = ballot_one_two(ranking)
             elif voting_rule == PLURALITY:
                 d_ranking_ballot[ranking] = ballot_two(ranking)
             else:
                 raise NotImplementedError
         else:
             d_ranking_ballot[ranking] = UTILITY_DEPENDENT
     # Call parent class
     super().__init__(d_ranking_ballot=d_ranking_ballot,
                      d_weak_order_ballot=d_weak_order_ballot,
                      profile=profile,
                      voting_rule=voting_rule)
    def tau_fanatic(self):
        """Tau-vector associated to fanatic voting.

        Returns
        -------
        TauVector
            In Approval or Plurality, all voters approve of their top candidate only. In Anti-Plurality, they all
            disapprove of their bottom candidate, i.e. they approve their two first candidates.
        """
        t = self.d_ballot_share_weak_voters_fanatic.copy()
        if self.voting_rule in {APPROVAL, PLURALITY}:
            for ranking, share in self.d_ranking_share.items():
                t[ballot_one(ranking)] += share
        elif self.voting_rule == ANTI_PLURALITY:
            for ranking, share in self.d_ranking_share.items():
                t[ballot_one_two(ranking)] += share
        else:
            raise NotImplementedError
        return TauVector(t, voting_rule=self.voting_rule, symbolic=self.symbolic)
Esempio n. 7
0
 def __init__(self,
              d_ranking_ballot,
              d_weak_order_ballot=None,
              profile=None,
              voting_rule=None):
     """
         >>> strategy = StrategyOrdinal({'abc': 'non_existing_ballot'})
         Traceback (most recent call last):
         ValueError: Unknown strategy: non_existing_ballot
     """
     voting_rule = self._get_voting_rule_(profile, voting_rule)
     # Prepare the dictionary of thresholds
     d_ranking_threshold = DictPrintingInOrderIgnoringZeros()
     for ranking, ballot in d_ranking_ballot.items():
         if ballot == '':
             d_ranking_threshold[ranking] = None
         elif ballot == ballot_one(ranking) and voting_rule in {
                 APPROVAL, PLURALITY
         }:
             d_ranking_threshold[ranking] = 1
         elif ballot == ballot_two(ranking) and voting_rule == PLURALITY:
             d_ranking_threshold[ranking] = 0
         elif (ballot
               in {ballot_one_two(ranking),
                   ballot_one_two(ranking)[::-1]}
               and voting_rule in {APPROVAL, ANTI_PLURALITY}):
             d_ranking_threshold[ranking] = 0
         elif (ballot in {
                 ballot_one_three(ranking),
                 ballot_one_three(ranking)[::-1]
         } and voting_rule == ANTI_PLURALITY):
             d_ranking_threshold[ranking] = 1
         else:
             raise ValueError('Unknown strategy: ' + ballot)
     # Call parent class
     super().__init__(d=d_ranking_threshold,
                      d_weak_order_ballot=d_weak_order_ballot,
                      profile=profile,
                      voting_rule=voting_rule)
Esempio n. 8
0
    def tau_fanatic(self):
        """Tau-vector associated to fanatic voting.

        Returns
        -------
        TauVector
            * In Approval or Plurality, all voters approve of their top candidate only,
            * In Anti-plurality, all voters vote against their bottom candidate (i.e. for the other two).

        Notes
        -----
        In Plurality and Anti-plurality, sincere and fanatic voting are the same. They differ only in Approval.
        """
        t = self.d_ballot_share_weak_voters_fanatic.copy()
        for ranking, share in self.d_ranking_share.items():
            if self.voting_rule in {APPROVAL, PLURALITY}:
                t[ballot_one(ranking)] += share
            elif self.voting_rule == ANTI_PLURALITY:
                t[ballot_one_two(ranking)] += self.d_ranking_share[ranking]
            else:
                raise NotImplementedError
        return TauVector(t, voting_rule=self.voting_rule, symbolic=self.symbolic)
Esempio n. 9
0
 def __init__(self,
              d_ranking_ballot,
              d_weak_order_ballot=None,
              profile=None,
              voting_rule=None):
     """
         >>> strategy = StrategyTwelve({'non_existing_ranking': 'utility-dependent'})
         Traceback (most recent call last):
         ValueError: Unknown key: non_existing_ranking
         >>> strategy = StrategyTwelve({'abc': 'non_existing_ballot'})
         Traceback (most recent call last):
         ValueError: Unknown strategy: non_existing_ballot
     """
     voting_rule = self._get_voting_rule_(profile, voting_rule)
     # Populate the dictionary and check for typos in the input
     self.d_ranking_ballot = DictPrintingInOrderIgnoringZeros(
         {ranking: ''
          for ranking in RANKINGS})
     for ranking, ballot in d_ranking_ballot.items():
         # Sanity checks
         if ranking not in RANKINGS:
             raise ValueError('Unknown key: ' + ranking)
         if voting_rule == APPROVAL:
             authorized_ballots = {
                 ballot_one(ranking),
                 ballot_one_two(ranking),
                 ballot_one_two(ranking)[::-1], '', UTILITY_DEPENDENT
             }
         elif voting_rule == PLURALITY:
             authorized_ballots = {
                 ballot_one(ranking),
                 ballot_two(ranking), '', UTILITY_DEPENDENT
             }
         elif voting_rule == ANTI_PLURALITY:
             authorized_ballots = {
                 ballot_one_two(ranking),
                 ballot_one_two(ranking)[::-1],
                 ballot_one_three(ranking),
                 ballot_one_three(ranking)[::-1], '', UTILITY_DEPENDENT
             }
         else:
             raise NotImplementedError
         if ballot not in authorized_ballots:
             raise ValueError('Unknown strategy: ' + ballot)
         # Record the ballot
         self.d_ranking_ballot[
             ranking] = ballot if ballot == UTILITY_DEPENDENT else sort_ballot(
                 ballot)
     # Weak orders
     self.d_weak_order_ballot = DictPrintingInOrderIgnoringZeros(
         {weak_order: ''
          for weak_order in WEAK_ORDERS_WITHOUT_INVERSIONS})
     if d_weak_order_ballot:
         if voting_rule == APPROVAL:
             for weak_order, ballot in d_weak_order_ballot.items():
                 if ballot != '':
                     raise ValueError(
                         'In Approval, you should not specify ballots for weak orders.'
                     )
         elif voting_rule == PLURALITY:
             for weak_order, ballot in d_weak_order_ballot.items():
                 if not is_weak_order(weak_order):
                     raise ValueError('Unknown key: ' + weak_order)
                 elif is_hater(weak_order):
                     possible_ballots = {
                         weak_order[0], weak_order[2], SPLIT
                     }
                     if ballot not in possible_ballots:
                         raise ValueError('Unknown strategy: ' + ballot)
                     self.d_weak_order_ballot[sort_weak_order(
                         weak_order)] = ballot
                 else:  # is_lover(weak_order)
                     if ballot != '':
                         raise ValueError(
                             'In Plurality, you should not specify ballots for "lovers" (e.g. a>b~c).'
                         )
         elif voting_rule == ANTI_PLURALITY:
             for weak_order, ballot in d_weak_order_ballot.items():
                 if not is_weak_order(weak_order):
                     raise ValueError('Unknown key: ' + weak_order)
                 elif is_lover(weak_order):
                     possible_ballots = {
                         sort_ballot(weak_order[0] + weak_order[2]),
                         sort_ballot(weak_order[0] + weak_order[4]), SPLIT
                     }
                     if ballot != SPLIT:
                         ballot = sort_ballot(ballot)
                     if ballot not in possible_ballots:
                         raise ValueError('Unknown strategy: ' + ballot +
                                          ' for ' + weak_order)
                     self.d_weak_order_ballot[sort_weak_order(
                         weak_order)] = ballot
                 else:  # is_hater(weak_order)
                     if ballot != '':
                         raise ValueError(
                             'In Anti-Plurality, you should not specify ballots '
                             'for "haters" (e.g. a~b>c).')
         else:
             raise NotImplementedError
     # Call parent class
     super().__init__(profile=profile, voting_rule=voting_rule)