def tau_strategic(self, strategy): """Tau-vector associated to a strategy (fully strategic voting). Parameters ---------- strategy : StrategyThreshold A strategy that specifies at least all the rankings that are present in the profile. If some voters have a utility for their second candidate that is equal to the utility threshold of the strategy, then the ratio of optimistic voters must be specified. Returns ------- TauVector Tau-vector associated to this profile and strategy `strategy`. """ assert self.voting_rule == strategy.voting_rule t = self.d_ballot_share_weak_voters_strategic(strategy) for ranking, threshold in strategy.d_ranking_threshold.items(): if self.d_ranking_share[ranking] == 0: continue t[ballot_low_u(ranking, self.voting_rule)] += self.have_ranking_with_utility_below_u(ranking, u=threshold) t[ballot_high_u(ranking, self.voting_rule)] += self.have_ranking_with_utility_above_u(ranking, u=threshold) share_limit_voters = self.have_ranking_with_utility_u(ranking, u=threshold) if share_limit_voters != 0: ratio_optimistic = strategy.d_ranking_ratio_optimistic[ranking] t[ballot_low_u(ranking, self.voting_rule)] += self.ce.multiply_with_absorbing_zero( share_limit_voters, ratio_optimistic) t[ballot_high_u(ranking, self.voting_rule)] += self.ce.multiply_with_absorbing_zero( share_limit_voters, 1 - ratio_optimistic) return TauVector(t, voting_rule=self.voting_rule, symbolic=self.symbolic)
def possible_ballots(ranking): try: return [self.d_ranking_fixed_strategy[ranking]] except KeyError: pass if self.profile is not None and self.profile.d_ranking_share[ ranking] == 0: return [''] return [ ballot_low_u(ranking, self.voting_rule), ballot_high_u(ranking, self.voting_rule) ]
def ballot(self): """str : This can be a valid ballot or ``'utility-dependent'``. """ if isnan(self.utility_threshold): raise AssertionError('Unable to compute utility threshold' ) # pragma: no cover - Should never happen elif self.ce.look_equal(self.utility_threshold, 1): return ballot_low_u(self.ranking, self.voting_rule) elif self.ce.look_equal(self.utility_threshold, 0, abs_tol=1E-9): return ballot_high_u(self.ranking, self.voting_rule) else: assert 0 <= self.utility_threshold <= 1 return UTILITY_DEPENDENT
def possible_ballots(ranking): try: return [self.d_ranking_fixed_strategy[ranking]] except KeyError: pass if self.profile is not None: share_ranking_1 = self.profile.d_type_share[ranking[0] + '_' + ranking[1:]] share_ranking_12 = self.profile.d_type_share[ranking[0:2] + '_' + ranking[2]] strategy_1 = ballot_low_u(ranking, self.voting_rule) strategy_12 = ballot_high_u(ranking, self.voting_rule) if share_ranking_1 > 0 and share_ranking_12 > 0: return [strategy_1, strategy_12, UTILITY_DEPENDENT] elif share_ranking_1 > 0 or share_ranking_12 > 0: return [strategy_1, strategy_12] else: return [''] else: return [ ballot_low_u(ranking, self.voting_rule), ballot_high_u(ranking, self.voting_rule), UTILITY_DEPENDENT ]
def tau_strategic(self, strategy): """Tau-vector associated to a strategy. Parameters ---------- strategy : StrategyTwelve A strategy that specifies at least all the rankings that are present in the profile. Returns ------- TauVector Tau-vector associated to this profile and strategy `strategy`. 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'}) >>> tau_strategic = profile.tau_strategic(strategy) >>> print(tau_strategic) <ab: 1/10, ac: 1/10, b: 3/5, c: 1/5> ==> b """ assert self.voting_rule == strategy.voting_rule t = self.d_ballot_share_weak_voters_strategic(strategy) 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 ballot == UTILITY_DEPENDENT: t[ballot_low_u(ranking, self.voting_rule )] += self.have_ranking_with_utility_below_u( ranking, u=.5) t[ballot_high_u(ranking, self.voting_rule )] += self.have_ranking_with_utility_above_u( ranking, u=.5) else: t[ballot] += self.d_ranking_share[ranking] return TauVector(t, voting_rule=self.voting_rule, symbolic=self.symbolic)
def random_tau_undominated(self): """Random tau based on undominated ballots. This is used, for example, in :meth:`~poisson_approval.ProfileCardinal.iterated_voting`. Returns ------- TauVector A random tau-vector. Independently for each ranking, a proportion uniformly drawn in [0, 1] of voters use one undominated ballot, and the rest use the other undominated ballot. For example, in Approval voting, voters with ranking `abc` are randomly split between ballots `a` and `ab`. """ d = {ballot: 0 for ballot in BALLOTS_WITHOUT_INVERSIONS} for ranking, share in self.d_ranking_share.items(): r = random.random() d[ballot_low_u(ranking, self.voting_rule)] += r * share d[ballot_high_u(ranking, self.voting_rule)] += (1 - r) * share for weak_order, share in self.d_weak_order_share.items(): if is_lover(weak_order): if self.voting_rule in {APPROVAL, PLURALITY}: d[weak_order[0]] += share elif self.voting_rule == ANTI_PLURALITY: r = random.random() d[sort_ballot(weak_order[0] + weak_order[2])] += r * share d[sort_ballot(weak_order[0] + weak_order[4])] += (1 - r) * share else: raise NotImplementedError else: # is_hater(weak_order) if self.voting_rule == PLURALITY: r = random.random() d[weak_order[0]] += r * share d[weak_order[2]] += (1 - r) * share elif self.voting_rule in {APPROVAL, ANTI_PLURALITY}: d[sort_ballot(weak_order[0] + weak_order[2])] += share else: raise NotImplementedError return TauVector(d, voting_rule=self.voting_rule, symbolic=self.symbolic)