---
title: "Introduction to TheOrdinals: consensus for preference-approvals"
author: "Alessandro Albano, Maurizio Romano"
output: rmarkdown::html_vignette
bibliography: null
vignette: >
  %\VignetteIndexEntry{Introduction to TheOrdinals: consensus for preference-approvals}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(TheOrdinals)
```

## Preference-approvals

A *preference-approval* is a pair $(\pi, A)$ where $\pi$ is a (weak) ranking of
$n$ alternatives and $A$ is the subset of *approved* alternatives. The two
components must be consistent: approved alternatives are ranked above unapproved
ones, and tied alternatives share the same approval status (Definition 1 of
Albano and Romano, 2026).

Throughout the package a set of $m$ preference-approvals is stored as a numeric
matrix with $2n$ columns: the first $n$ columns hold the ranking (positions,
with ties allowed) and the last $n$ columns hold the approval indicators
(`1` approved, `0` not approved). For example, four voters over four
alternatives:

```{r data}
x <- rbind(
  c(1, 2, 3, 4, 1, 1, 0, 0),
  c(2, 1, 3, 4, 1, 0, 0, 0),
  c(1, 2, 4, 3, 1, 1, 0, 0),
  c(1, 3, 2, 4, 1, 1, 1, 0)
)
x
```

The consistency of a single preference-approval can be checked with
`is_consistent()`:

```{r consistent}
is_consistent(c(1, 2, 3, 4), c(1, 1, 0, 0))  # admissible
is_consistent(c(1, 2, 3, 4), c(0, 1, 0, 0))  # not admissible
```

Given a ranking, `find_approval()` enumerates the approvals compatible with it,
and `pa_universe()` builds the whole universe of preference-approvals on $n$
alternatives:

```{r universe}
find_approval(c(1, 2, 2, 3))
dim(pa_universe(3))
```

## Distance between preference-approvals

The disagreement between two preference-approvals is measured by the family of
distances $d_\lambda$ of Erdamar et al. (2014), a convex combination of the
normalised Kemeny distance on the ranking component and the normalised Hamming
distance on the approval component:

$$
  d_\lambda\big((\pi_1, A_1), (\pi_2, A_2)\big)
  = \lambda \, d_R + (1 - \lambda)\, d_A, \qquad \lambda \in [0, 1].
$$

The function `pref_dist()` returns the matrix of pairwise distances:

```{r dist}
round(pref_dist(x), 3)              # lambda = 0.5
round(pref_dist(x, lambda = 0.8), 3)
```

## The DIVA consensus

DIVA (Divide and Conquer for Preference-Approvals) returns the
preference-approval that minimises the average distance $d_\lambda$ to the set of
voters. The result is always admissible.

```{r diva-small}
res <- diva(x, algorithm = "quick")
res
res$d_lambda
```

### French Presidential Election (2002)

The dataset `french_election_2002` contains the admissible preference-approvals
on the 15 candidates of the first round of the 2002 French presidential
election.

```{r french}
data(french_election_2002)
dim(french_election_2002)
fc <- diva(french_election_2002, algorithm = "quick")
fc$d_lambda
```

The consensus ranks Lionel Jospin first; the approved candidates are those whose
consensus rank is among the top positions:

```{r french-result}
n <- 15
cons <- fc$consensus[1, ]
data.frame(
  candidate = colnames(french_election_2002)[1:n],
  rank      = as.numeric(cons[1:n]),
  approved  = as.numeric(cons[(n + 1):(2 * n)])
)
```

### Sensitivity to the weighting parameter

`diva_sensitivity()` reports the achieved average distance over a grid of
$\lambda$, showing how the relative weight of the ranking and the approval
components affects the consensus:

```{r sensitivity, fig.width = 6, fig.height = 4, fig.alt = "DIVA consensus distance as a function of lambda"}
s <- diva_sensitivity(french_election_2002)
plot(s$lambda, s$d_lambda, type = "b", pch = 19,
     xlab = expression(lambda), ylab = expression(D[lambda]),
     main = "DIVA consensus distance vs lambda")
```

### Formula 1 World Championship (1950)

The dataset `formula1_1950` reads the classification of each of the 7 Grands
Prix of the 1950 season as a ranking of 81 drivers, with the top five finishers
approved. With 81 alternatives the consensus search is heavier, so the call
below is shown but not executed in this vignette:

```{r f1, eval = FALSE}
data(formula1_1950)
diva(formula1_1950, algorithm = "quick")
```

## References

- Albano, A. and Romano, M. (2026). A distance-based aggregation method for
  finding consensus in preference-approvals. *Advances in Data Analysis and
  Classification*. <https://doi.org/10.1007/s11634-025-00663-4>
- Erdamar, B., García-Lapresta, J. L., Pérez-Román, D. and Sanver, M. R.
  (2014). Measuring consensus in a preference-approval context. *Mathematical
  Social Sciences*, 39–46. <https://doi.org/10.1016/j.mathsocsci.2013.10.005>
