RuleIteratedElimination

class whalrus.RuleIteratedElimination(*args, base_rule: whalrus.rules.rule.Rule = None, elimination: whalrus.eliminations.elimination.Elimination = None, propagate_tie_break=True, **kwargs)[source]

A rule by iterated elimination (such as RuleIRV, RuleCoombs, RuleNanson, etc.)

Parameters
  • args – Cf. parent class.

  • base_rule (Rule) – The rule used at each round to determine the eliminated candidate(s). Unlike for RuleSequentialElimination, all the rounds use the same voting rule.

  • elimination (Elimination) – The elimination algorithm. Default: EliminationLast(k=1).

  • propagate_tie_break (bool) – If True (default), then the tie-breaking rule of this object is also used for the base rule (cf. below).

  • kwargs – Cf. parent class.

Examples

>>> irv = RuleIteratedElimination(['a > b > c', 'b > a > c', 'c > a > b'], weights=[2, 3, 4],
...                                 base_rule=RulePlurality())
>>> irv.eliminations_[0].rule_.gross_scores_
{'a': 2, 'b': 3, 'c': 4}
>>> irv.eliminations_[1].rule_.gross_scores_
{'b': 5, 'c': 4}
>>> irv.eliminations_[2].rule_.gross_scores_
{'b': 9}
>>> irv.winner_
'b'

Remark: there exists a shortcut for the above rule in particular, the class RuleIRV.

By default, propagate_tie_break is True. So if you want to specify a tie-breaking rule, just do it in the parameters of this object, and it will also be used in the base rule. This is probably what you want to do:

>>> irv = RuleIteratedElimination(['a > c > b', 'b > a > c', 'c > a > b'], weights=[1, 2, 1],
...                                 base_rule=RulePlurality(), tie_break=Priority.ASCENDING)
>>> irv.eliminations_[0].rule_.gross_scores_
{'a': 1, 'b': 2, 'c': 1}
>>> irv.eliminations_[1].rule_.gross_scores_
{'a': 2, 'b': 2}
>>> irv.eliminations_[2].rule_.gross_scores_
{'a': 4}
>>> irv.winner_
'a'

If propagate_tie_break is False, then there is a subtlety between the tie-breaking rule of this object, and the tie-breaking rule of the base rule. The following (somewhat contrived) example illustrates the respective roles of the two tie-breaking rules.

>>> rule = RuleIteratedElimination(
...     ['a', 'b', 'c', 'd', 'e'], weights=[3, 2, 2, 2, 1],
...     tie_break=Priority.DESCENDING, propagate_tie_break=False,
...     base_rule=RulePlurality(tie_break=Priority.ASCENDING), elimination=EliminationLast(k=2))
>>> rule.eliminations_[0].rule_.gross_scores_
{'a': 3, 'b': 2, 'c': 2, 'd': 2, 'e': 1}

With the worst score, e is eliminated anyway, but we need to eliminate a second candidate because k = 2. In Plurality, b, c and d are tied, but since Plurality’s tie-breaking rule is ASCENDING, candidates b or c get an advantage over d. Hence d is eliminated:

>>> rule.eliminations_[0].eliminated_
{'d', 'e'}

Note that the tie-breaking rule of the base rule (here Plurality) is always sufficient to compute the weak order over the candidates. This order may be finer than the elimination order, because being eliminated at the same time does not mean being tied, as d and e illustrate here:

>>> rule.order_
[{'a'}, {'b', 'c'}, {'d'}, {'e'}]

So, where does the tie-breaking rule of this object come in? It is simply used to get the strict order over the candidates, as usual in a Rule. In our example, since it is DESCENDING, candidate c gets an advantage over b:

>>> rule.strict_order_
['a', 'c', 'b', 'd', 'e']
property cotrailers_

“Cotrailers” of the election, i.e. the candidates that fare worst in the election. This is the last equivalence class in order_. For example, in RuleScoreNum, it is the candidates that are tied for the worst score.

Type

NiceSet

property cowinners_

Cowinners of the election, i.e. the candidates that fare best in the election.. This is the first equivalence class in order_. For example, in RuleScoreNum, it is the candidates that are tied for the best score.

Type

NiceSet

property eliminations_

The elimination rounds. A list of Elimination objects. The first one corresponds to the first round, etc.

Type

list

property n_candidates_

Number of candidates.

Type

int

property strict_order_

Result of the election as a strict order over the candidates. The first element is the winner, etc. This may use the tie-breaking rule.

Type

list

property trailer_

The “trailer” of the election. This is the last candidate in strict_order_ and also the unfavorable choice of the tie-breaking rule in cotrailers_.

Type

object

property winner_

The winner of the election. This is the first candidate in strict_order_ and also the choice of the tie-breaking rule in cowinners_.

Type

object