# Selector combining

Heavy use of custom gates can lead to a circuit defining many binary selectors, which would increase proof size and verification time.

This section describes an optimization, applied automatically by halo2, that combines binary selector columns into fewer fixed columns.

The basic idea is that if we have $ℓ$ binary selectors labelled $1,…,ℓ$ that are enabled on disjoint sets of rows, then under some additional conditions we can combine them into a single fixed column, say $q$, such that: $q={k,0, if the selector labelledkis1if all these selectors are0. $

However, the devil is in the detail.

The halo2 API allows defining some selectors to be "simple selectors", subject to the following condition:

Every polynomial constraint involving a simple selector $s$ must be of the form $s⋅t=0,$ where $t$ is a polynomial involving

nosimple selectors.

Suppose that $s$ has label $k$ in some set of $ℓ$ simple selectors that are combined into $q$ as above. Then this condition ensures that replacing $s$ by $q⋅∏_{1≤h≤ℓ,h=k}(h−q)$ will not change the meaning of any constraints.

It would be possible to relax this condition by ensuring that every use of a binary selector is substituted by a precise interpolation of its value from the corresponding combined selector. However,

- the restriction simplifies the implementation, developer tooling, and human understanding and debugging of the resulting constraint system;
- the scope to apply the optimization is not impeded very much by this restriction for typical circuits.

Note that replacing $s$ by $q⋅∏_{1≤h≤ℓ,h=k}(h−q)$ will increase the degree of constraints selected by $s$ by $ℓ−1$, and so we must choose the selectors that are combined in such a way that the maximum degree bound is not exceeded.

## Identifying selectors that can be combined

We need a partition of the overall set of selectors $s_{0},…,s_{m−1}$ into subsets (called "combinations"), such that no two selectors in a combination are enabled on the same row.

Labels must be unique within a combination, but they are not unique across combinations. Do not confuse a selector's index with its label.

Suppose that we are given $max_degree$, the degree bound of the circuit.

We use the following algorithm:

- Leave nonsimple selectors unoptimized, i.e. map each of them to a separate fixed column.
- Check (or ensure by construction) that all polynomial constraints involving each simple selector $s_{i}$ are of the form $s_{i}⋅t_{i,j}=0$ where $t_{i,j}$ do not involve any simple selectors. For each $i$, record the maximum degree of any $t_{i,j}$ as $d_{i}$.
- Compute a binary "exclusion matrix" $X$ such that $X_{j,i}$ is $1$ whenever $i=j$
and $s_{i}$ and $s_{j}$ are enabled on the same row; and $0$ otherwise.
Since $X$ is symmetric and is zero on the diagonal, we can represent it by either its upper or lower triangular entries. The rest of the algorithm is guaranteed only to access only the entries $X_{j,i}$ where $j>i$.

- Initialize a boolean array $added_{0..k−1}$ to all $false$.
$added_{i}$ will record whether $s_{i}$ has been included in any combination.

- Iterate over the $s_{i}$ that have not yet been added to any combination:
- a. Add $s_{i}$ to a fresh combination $c$, and set $added_{i}=true$.
- b. Let mut $d:=d_{i}−1$.
$d$ is used to keep track of the largest degree,

*excluding*the selector expression, of any gate involved in the combination $c$ so far. - c. Iterate over all the selectors $s_{j}$ for $j>i$ that can potentially join $c$,
i.e. for which $added_{j}$ is false:
- i. (Optimization) If $d+len(c)=max_degree$, break to the outer loop, since no more selectors can be added to $c$.
- ii. Let $d_{new}=max(d,d_{j}−1)$.
- iii. If $X_{j,i_{′}}$ is $true$ for any $i_{′}$ in $c$, or if
$d_{new}+(len(c)+1)>max_degree$, break to the outer
loop.
$d_{new}+(len(c)+1)$ is the maximum degree,

*including*the selector expression, of any constraint that would result from adding $s_{j}$ to the combination $c$. - iv. Set $d:=d_{new}$.
- v. Add $s_{j}$ to $c$ and set $added_{j}:=true$.

- d. Allocate a fixed column $q_{c}$, initialized to all-zeroes.
- e. For each selector $s_{′}∈c$:
- i. Label $s_{′}$ with a distinct index $k$ where $1≤k≤len(c)$.
- ii. Record that $s_{′}$ should be substituted with $q_{c}⋅∏_{1≤h≤len(c),h=k}(h−q_{c})$ in all gate constraints.
- iii. For each row $r$ such that $s_{′}$ is enabled at $r$, assign the value $k$ to $q_{c}$ at row $r$.

The above algorithm is implemented in
halo2_proofs/src/plonk/circuit/compress_selectors.rs.
This is used by the `compress_selectors`

function of
halo2_proofs/src/plonk/circuit.rs
which does the actual substitutions.

## Writing circuits to take best advantage of selector combining

For this optimization it is beneficial for a circuit to use simple selectors as far as possible, rather than fixed columns. It is usually not beneficial to do manual combining of selectors, because the resulting fixed columns cannot take part in the automatic combining. That means that to get comparable results you would need to do a global optimization manually, which would interfere with writing composable gadgets.

Whether two selectors are enabled on the same row (and so are inhibited from being combined) depends on how regions are laid out by the floor planner. The currently implemented floor planners do not attempt to take this into account. We suggest not worrying about it too much — the gains that can be obtained by cajoling a floor planner to shuffle around regions in order to improve combining are likely to be relatively small.