# Tutorial¶

```
>>> from whalrus import *
```

## Quick start¶

Some simple elections:

```
>>> RulePlurality(['a', 'a', 'b', 'c']).winner_
'a'
>>> RuleBorda(['a > b > c', 'b > c > a']).gross_scores_
{'a': 2, 'b': 3, 'c': 1}
```

Elections can optionally have weights and voter names:

```
>>> RulePlurality(
... ['a', 'a', 'b', 'c'], weights=[1, 1, 3, 2],
... voters=['Alice', 'Bob', 'Cate', 'Dave']
... ).winner_
'b'
```

The tie-breaking rule can be specified:

```
>>> RulePlurality(['a', 'a', 'b', 'b', 'c'], tie_break=Priority.ASCENDING).winner_
'a'
```

## Computed attributes of an election¶

>>> plurality = RulePlurality(['a', 'a', 'b', 'b', 'c'], tie_break=Priority.ASCENDING)Once the election is defined, you can access its computed attributes, whose names end with an underscore:

>>> plurality.candidates_ {'a', 'b', 'c'} >>> plurality.gross_scores_ {'a': 2, 'b': 2, 'c': 1} >>> plurality.scores_ {'a': Fraction(2, 5), 'b': Fraction(2, 5), 'c': Fraction(1, 5)} >>> plurality.best_score_ Fraction(2, 5) >>> plurality.worst_score_ Fraction(1, 5) >>> plurality.order_ [{'a', 'b'}, {'c'}] >>> plurality.strict_order_ ['a', 'b', 'c'] >>> plurality.cowinners_ {'a', 'b'} >>> plurality.winner_ 'a' >>> plurality.cotrailers_ {'c'} >>> plurality.trailer_ 'c'

## General syntax¶

In the most general syntax, firstly, you define the rule and enter its options:

```
>>> plurality = RulePlurality(tie_break=Priority.ASCENDING)
```

Secondly, you use it as a callable to load a particular election (profile, set of candidates):

```
>>> plurality(ballots=['a', 'b', 'c'], weights=[2, 2, 1], voters=['Alice', 'Bob', 'Cate'],
... candidates={'a', 'b', 'c', 'd'}) # doctest:+ELLIPSIS
<... object at ...>
```

Finally, you can access the computed variables:

```
>>> plurality.gross_scores_
{'a': 2, 'b': 2, 'c': 1, 'd': 0}
```

Later, if you wish, you can load another profile with the same voting rule, and so on.

## Under the hood¶

A `whalrus.Ballot`

contains the message emitted by the voter, but also some contextual information such as the
set of candidates that were available at the moment when she cast her ballot:

```
>>> ballot = BallotOrder('a > b ~ c')
>>> ballot
BallotOrder(['a', {'b', 'c'}], candidates={'a', 'b', 'c'})
```

This architecture allows Whalrus to deal with asynchronous elections where the set of candidates may vary during the election itself (such as some asynchronous online polls).

A `whalrus.Profile`

contains a list of `whalrus.Ballot`

objects, a list of weights and a list of voters:

```
>>> profile = Profile(['a > b ~ c', 'a ~ b > c'])
>>> profile.ballots[0]
BallotOrder(['a', {'b', 'c'}], candidates={'a', 'b', 'c'})
>>> profile.weights
[1, 1]
>>> profile.voters
[None, None]
```

Internally, a voting rule is always applied to a `whalrus.Profile`

. Hence, if the inputs are given in a “loose”
format, they are converted to a `whalrus.Profile`

:

```
>>> borda = RuleBorda(['a > b ~ c', 'a ~ b > c'])
>>> borda.profile_converted_ # doctest:+ELLIPSIS
Profile(ballots=[BallotOrder(['a', {'b', 'c'}], candidates={'a', 'b', 'c'}), ...)
```

Under the hood, some conversions are performed so that a variety of inputs are understood by Whalrus. In the
example above, the first ballot was manually entered as `a > b ~ c`

. In the absence of other information, Whalrus
then considered that only candidates a, b and c were available when this voter cast her ballot. If you want to
give more detailed information, the most general syntax consists in using the constructors of classes
`whalrus.Profile`

, `whalrus.Ballot`

and their subclasses:

```
>>> a_more_complex_ballot = BallotOrder('a > b ~ c', candidates={'a', 'b', 'c', 'd', 'e'})
```

The ballot above means that the voter emitted the message ‘a > b ~ c’ in a context where the candidates d and e where also available, i.e. she deliberately abstained about these two candidates.

## Change the candidates¶

It is possible to change the set of candidates, compared to when the voters cast their ballots.

```
>>> profile = Profile(['a > b > c', 'a ~ b > c'])
>>> RulePlurality(profile, candidates={'b', 'c'}).gross_scores_
{'b': 2, 'c': 0}
```