Skip to content

Commit

Permalink
Improve accuracy of voting types
Browse files Browse the repository at this point in the history
  • Loading branch information
NateWilliams2 committed Mar 27, 2024
1 parent fc565b1 commit 4a08096
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 48 deletions.
4 changes: 2 additions & 2 deletions docs/protocol/ballot-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The protocol is composed by a set of numeric and boolean variables that restrict
- `uint8 maxCount`
Max number of fields per ballot. 1 <= maxCount <= 100.
- `uint8 maxValue`
Determines the acceptable maximum value for all fields.
Determines the acceptable maximum value for all fields. If `maxValue` is set to `0`, the results are aggregated.
- `uint8 minValue`
Determines the acceptable minimum value for all fields.
- `bool uniqueValues`
Expand Down Expand Up @@ -272,7 +272,7 @@ Candidate 5 has won the CEO position, whereas COO is tied between candidates 2,

## Vocdoni results interpretation

Results interpretation is not part of the ballot protocol, but it informs how the protocol should be understood and displayed. The Process Metadata has a couple of flags describing the expected interpretation.
Results interpretation is not part of the ballot protocol, but it informs how the protocol should be understood and displayed by clients. The Process Metadata has a couple of flags that can be used to tell clients how to interpret a results matrix:

```json
"results": {
Expand Down
11 changes: 3 additions & 8 deletions docs/sdk/integration-details/voting-types/quadratic.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
# Quadratic voting

Quadratic voting is a voting mechanism that allows individuals to express their preferences on different issues with
more granularity and intensity. In quadratic voting, voters are allocated a fixed number of voting credits, and they can
distribute those credits across various options or issues in a quadratic manner. This means that voters can assign more
credits to options they care strongly about while still being able to express preferences on multiple issues.

The quadratic aspect of the system ensures that the cost of allocating additional credits increases quadratically, which
helps prevent a small number of voters from dominating the decision-making process. Quadratic voting aims to promote a
more accurate representation of individual preferences and allocate resources based on the collective intensity of
preferences rather than just a simple majority rule.
more granularity and intensity. In quadratic voting, voters are allocated a fixed number of voting credits, and they can distribute those credits across various options or issues. This means that voters can assign more credits to options they care strongly about while still being able to express preferences on multiple issues.

The quadratic aspect of the system ensures that the cost of allocating additional credits increases quadratically, which helps prevent a small number of voters from dominating the decision-making process. Quadratic voting aims to promote a more accurate representation of individual preferences and allocate resources based on the collective intensity of preferences rather than just a simple majority rule.

See:

Expand Down
9 changes: 2 additions & 7 deletions docs/sdk/integration-details/voting-types/single-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This voting system supports **one** or **multiple questions**.

See:

- [Complete example](https://github.com/vocdoni/vocdoni-sdk/blob/main/examples/typescript/src/index.ts)
- [Ballot protocol implementation][protocol-single-choice]

## Setting up the election
Expand Down Expand Up @@ -70,12 +71,6 @@ Take note that the question values are **incremental** and the initial value **

:::

:::tip Multiple questions support

This election type can accommodate multiple questions.

:::

:::caution Not all elections type supports multiple questions!

This is the sole type of election that supports multiple questions. Other election types, such as `ranked`, `quadratic`,
Expand Down Expand Up @@ -120,7 +115,7 @@ For single question is same philosophy, you could configure the election as:
maxValue: 3, // That accepts three choices
// ...
// And finally casting the vote
client.submitVote(new Vote([0, 2])); // Voting the third option
client.submitVote(new Vote([2])); // Voting the third option
```

:::
Expand Down
97 changes: 66 additions & 31 deletions docs/sdk/integration-details/voting-types/voting-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,65 +20,100 @@ additional votes on the same issue rises exponentially.
The configuration of these election types happens at the time of election creation using the SDK. Refer to the respective
documentation for the parameter requirements for each election type.

A comprehensive explanation of the parameters used in the ballot protocol can be found [here][ballot-protocol].
These voting types describe different sets of behavior that can be generated with the set of election parameters. A comprehensive explanation of the parameters used in the ballot protocol can be found [here][ballot-protocol].

## Results interpretation

The results are stored on the Vochain as a bi-dimensional array. Essentially, the ballot protocol is a system that
transforms a unidimensional array (a vote, e.g., `[1,4]`) into a bi-dimensional array of results (e.g., `[[2,5]]`).
The structure for individual ballots and the corresponding results can vary depending on the election parameters. For example, a vote envelope `[0, 2, 1]` could mean one of the following:
- 0 points for the first candidate, 2 points for the second candidate, 1 point for the third candidate
- first-choice selection for the first candidate, third-choice for the second candidate, and second-choice for the third
- choice of option `0` for the first question, option `2` for the second question, and option `1` for the third.

The interpretation of results is done on the user side, which receives the results from the SDK. The SDK provides
metadata about the election to facilitate understanding of the results. More details on interpreting results can be found [here][results-interpretation].
The interpretation of votes is done at the protocol-level, according to the election parameters. The results are stored on the Vochain as a bi-dimensional array. Essentially, the ballot protocol is a system that transforms a unidimensional array (a vote, e.g., `[1,4]`) into a bi-dimensional array of results (e.g., `[[2,5], [3,8]]`).

Here's a simple example to demonstrate how the result array can be interpreted in different ways, depending on the
election type:
The interpretation of this matrix of results is done on the client side, which receives the raw results from the SDK. The SDK also provides metadata about the election to facilitate understanding of the results. More details on interpreting results can be found [here][results-interpretation].

Consider a question where 2 candidates are ranked by preference, which is an example of `ranked voting`. The results
array might look like this:
Here's a simple example to demonstrate how the same result array can be interpreted in different ways, depending on the election type:

#### Linear-Weighted Choice Voting

Consider a single-choice question where three candidates are ranked by voters, each receiving a number of 'points' according to each voter's ranking. This is an example of `linear-weighted choice`. A results array with 10 votes might look like this:

```
[
[0, 0, 10],
[0, 10, 0],
[10, 0, 0]
[4, 6, 0],
[2, 4, 4],
[4, 0, 6]
]
```

Each row of this matrix represents a single candidate, and each column represents a chosen allocation of points. The numbers represent the total number of votes for that candidate/points combination.

In this scenario:

- 10 voters select the first candidate as third option
- 10 voters select the second candidate as second option
- 10 voters select the third candidate as first option
- The first candidate receives 4 0-point votes and 6 1-point votes
- The second candidate receives 2 0-point, 4 1-point, and 4 2-point votes
- The third candidate receives 4 0-point votes and 6 2-point votes

We can use this results matrix to calculate the total weighted sum for each candidate: the first candidate receives 6 points, the second candidate receives 12, and the third candidate receives 12. Candidates 2 and 3 tie. This results interpretation is "weighted," meaning each choice represents a quantified amount of preference, and we could aggregate the results into a single array of allocated points without losing any information:
```
[6, 12, 12]
```

:::note aggregated results
For all elections where `maxValue` is set to `0`, it is assumed that the election uses a weighted results system (like in this example). The aggregated results (`[6, 12, 12]`) are calculated on the indexer and reported as the official results.
:::

#### Ranked-Choice Voting

Now, let's examine another election type that can produce the same results array. For a question like "choose your 3
favorite colors out of 2", which is an example of `approval voting`, the results array may look like that:
Consider a single-choice question where three candidates are ranked by preference, and if no candidate receives more than 50% of the first-choice votes, second-choice votes are considered (a runoff election). This is one example of a `ranked voting` scheme. The results array could look identical to the one above:

```
[
[10, 0],
[0, 10],
[0, 10]
[4, 6, 0],
[2, 4, 4],
[4, 0, 6]
]
```

On this case, the results interpretation may vary:
Each row of this matrix represents a single candidate, and each column represents the choice (first, second, third). The numbers represent the total number of votes for that candidate/choice combination.

- 10 users give 0 points to first option
- 10 users give 1 point to second and third options

The examples above represent two methods for interpreting the results array. Additional examples are available for
different voting type result interpretations.
In this scenario:

:::note Weighted results are calculated on the indexer
- The first candidate receives 4 first-choice and 6 second-choice votes
- The second candidate receives 2 first-choice, 4 second-choice, and 4 third-choice votes
- The third candidate receives 6 first-choice and 4 third-choice votes

In a weighted election, the Vochain stores the envelope without calculating the weight of each voter. However, when
retrieving the results using the SDK, you will see the weights applied. The application of these weights is performed
by the vocdoni-node indexer, which calculates the weights for you.

The weights of each vote are stored in the envelope, which is saved on the Vochain.
The main difference between this example in the last is that each vote count has to be treated as a discrete piece of data rather than a value that can be combined arithmetically with others. This is because this election has a complex method for calculating the winner where first and second choices have different meanings rather than different amounts of the same meaning. The entire results matrix is needed in order to calculate a result.

:::tip ranked-choice
For ranked-choice, the `maxValue` parameter cannot equal zero to signify that values are discrete options, not weighted points.
:::

In this case, the first and third candidates tie with 40% of the vote each when only first-choice votes are considered. Thus we must consider a runoff using second-choice votes: the first candidate gets 60% of the second-choice votes, and the third candidate gets 0%. The first candidate wins the election.

#### Multiple Question

Now, let's consider an election with three questions, where each question has three options. Voters must select one of the three options for each question. This is a multiple-question, multiple-choice election.

```
[
[4, 6, 0],
[2, 4, 4],
[4, 0, 6]
]
```

Each row of this matrix represents a separate question, and each column represents the choice (first, second, third). The numbers represent the total number of votes for that question/choice combination.

In this scenario:

- For the first question, candidate 0 receives 4 votes and candidate 1 receives 6 (candidate 1 wins)
- For the second question, candidate 0 receives 2 votes, candidate 1 receives 4, and candidate 2 receives 4 (candidates 1 and 2 tie)
- For the third question, candidate 0 receives 4 votes and candidate 2 receives 6 (candidate 2 wins)

You can see how the same results matrix could represent a wide set of interpretations, and it is crucial to pay attention to the election parameters and original design of the election when displaying the results.

[ballot-protocol]: /protocol/ballot-protocol
[results-interpretation]: /protocol/ballot-protocol#vocdoni-results-interpretation
Expand Down
8 changes: 8 additions & 0 deletions docs/sdk/integration-details/voting-types/weighted.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,11 @@ second index.

The array `[ [ '4', '6' ] ]` encapsulates this result, which can be interpreted as "4 weighted votes for 'no' and 6
weighted votes for 'yes'".

:::tip
In a weighted election, the Vochain stores the envelope without calculating the weight of each voter. However, when
retrieving the results using the SDK, you will see the weights applied. The application of these weights is performed
by the vocdoni-node indexer, which calculates the weights for you.

The weights of each vote are stored in the envelope, which is saved on the Vochain.
:::

0 comments on commit 4a08096

Please sign in to comment.