Definition

Optimum contribution selection (OCS) is a breeding strategy that maximizes genetic gain (improvement) while simultaneously restricting the inbreeding, ensuring long-term genetic diversity. OCS aims to find the optimum number of offspring for each breeding individual and to determine if a selection candidate should be selected for breeding or not.


The OCS Framework

Mathematical Formulation

OCS was formalized by Meuwissen (1997) as a quadratic programming problem. The goal is to find a vector of contributions \(\mathbf{c}\) for each candidate such that:

\[\text{Maximize} \quad \mathbf{c}^\top \mathbf{g}\]

\[\text{Subject to} \quad \mathbf{c}^\top \mathbf{\frac{K}{2}} \mathbf{c} \leq F^*\]

\[\mathbf{1}^\top \mathbf{c} = 1, \quad \mathbf{c} \geq 0\]

Where:

  • \(\mathbf{c}\) — vector of genetic contributions of each candidate to the next generation
  • \(\mathbf{g}\) — vector of estimated breeding values (EBVs) or genetic merits
  • \(\mathbf{\frac{K}{2}}\) — relationship matrix (pedigree- or genomic-based) or coancestry
  • \(F^*\) — maximum allowable mean kinship (inbreeding constraint)

Any OCS algorithm would find the optimal contributions by solving the constrained optimization above. In practice, the contributions determine how many offspring each selected parent should produce.

Parents with high genetic merit and low relatedness to others receive higher contributions; parents that are highly related to the rest of the population receive lower contributions, even if their genetic merit is high.


The Pareto Frontier: Genetic Gain vs. Inbreeding

The Trade-off

OCS faces a fundamental tension between two objectives:

  • Maximize genetic gain → tends to concentrate selection on a few top individuals → increases coancestry
  • Minimize coancestry → spreads contributions evenly → reduces genetic gain

These two goals are fundamentally in tension. Pushing hard for genetic gain means repeatedly selecting the same top individuals, which drives coancestry up. Pushing hard to minimize coancestry forces the use of mediocre-but-unrelated individuals, sacrificing genetic progress.

This trade-off defines a Pareto frontier: a curve of optimal solutions where no improvement in one objective is possible without a cost to the other.

The Degree Parameter

Rather than asking the breeder to specify an abstract coancestry target, OCS implementations often allow the user to set a degree angle (0°–90°) that navigates the frontier:

Angle Behavior
Maximizes genetic gain (ignores inbreeding)
45° Balanced trade-off between gain and diversity
90° Minimizes inbreeding (ignores genetic gain)

The angle is converted to a coancestry target via a trigonometric mapping (sine in our case), which is then used as an upper bound in the optimization.


An implementation

The implementation explored here is the one from SimpleMating package (Peixoto et al. 2025). The function GOCS() is a wrapper around Optisel Package (Wellmann, 2019). There are three possibility in the function using the argument Target: To focus in maximizing genetic gain (MaxSel), to focus in minimize the inbreeding (MinInb), and to target both (both). In the latest, a degree has to be assigned in the argument Degree. This degree will tell the optimization function the weight to put in each part of the optimization (Maximize gain / minimize inbreeding).

MatePlan <- GOCS(Criterion = Crit, 
                     K = relMat, 
                     nMatings = 30, 
                     Target = "both", #MinInb, MaxSel, both
                     Degree = 90,
                     nProgeny = 1)

The Degree used when both are needed

Rather than asking the breeder to supply an abstract raw coancestry value, GOCS() lets them turn a dial from 0° to 90° to travel along the frontier.The mapping from angle to position on the frontier is done through a trigonometric function. Using cosine (the original behavior):

\[\text{CosPerc} = \cos\!\left(\theta \times \frac{\pi}{180}\right) \times 100\]

Inverting to sine (the updated behavior) simply swaps the extremes. For cosine, we have:

Angle (°) \(\cos(\theta)\) Position on frontier
0 1.00 Closest to MaxObj (maximize selection)
45 0.71 Balanced trade-off
90 0.00 Closest to MinObj (minimize inbreeding)

This makes Degree = 0 intuitively read as “no inbreeding control” and Degree = 90 as “maximum inbreeding control”, which aligns with how breeders tend to reason directionally. MaxObj and MinObj are arguments from OptiSel used internally in GOCS() function to model the Pareto Gain-Inbreeding.


The Full Interpolation

The interpolation does not operate on raw coancestry values. It works on coancestry rates — the per-generation change normalized by the available headroom (Falconer & Mackey, 1996):

\[\Delta F = \frac{F_{\text{future}} - F_{\text{current}}}{1 - F_{\text{current}}}\]

This is the standard quantitative genetics formulation for the rate of inbreeding change (Meuwissen, 1997). Normalizing by \((1 - F_{\text{current}})\) ensures that the interpolation is meaningful across populations at different baseline coancestry levels. A population already at high coancestry has less room to move, and the rate accounts for that.

Once coancestry rates are available for both extremes (values of inbreeding and genetic mean of the target population), the target rate is computed by linear interpolation weighted by the trigonometric percentage:

\[\Delta F_{\text{target}} = \Delta F_{\min} + \frac{100 - \text{SinPerc}}{100} \times (\Delta F_{\max} - \Delta F_{\min})\]

In plain language: start at the minimum-inbreeding rate, and slide toward the maximum-selection rate by a fraction determined by the angle.

Finally, the target rate is converted back to a raw coancestry value:

\[F_{\text{target}} = \Delta F_{\text{target}} \times (1 - F_{\text{current}}) + F_{\text{current}}\]

This value is then passed to opticont() (internal function from OptiSel) as an upper coancestry bound (ub.sKin) (internal argument from OptiSel). The optimizer finds the best possible selection criterion subject to not exceeding that coancestry ceiling — the constrained OCS problem.


The Mating Plan

As the OCS does not return a mating plan straight out of the optimization, internally the function GOCS() will create a mating plan based on the contributions from each parent.What are contributions?

After the OCS optimization, each candidate parent receives an optimum contribution value — a number between 0 and 1 that reflects how much of the next generation that individual should produce. Parents with high EBV and low relatedness receive higher contributions; highly related or low-merit individuals receive zero or near-zero contributions.

Here we simulate a small example with 8 parents and arbitrary contributions to show how GOCS() translates those numbers into a concrete mating plan.

# Eight parents and their optimum contributions (must sum to 1)
contributions <- data.frame(
  Parent       = paste0("Ind_", LETTERS[1:8]),
  Contribution = c(0.25, 0.20, 0.18, 0.15, 0.10, 0.07, 0.03, 0.02)
)

contributions
##   Parent Contribution
## 1  Ind_A         0.25
## 2  Ind_B         0.20
## 3  Ind_C         0.18
## 4  Ind_D         0.15
## 5  Ind_E         0.10
## 6  Ind_F         0.07
## 7  Ind_G         0.03
## 8  Ind_H         0.02

GOCS() calls process_optim(), which converts the fractional contributions into expected number of offspring slots using:

\[n_i = \text{round}(2 \times n_{\text{matings}} \times c_i)\]

The factor of 2 reflects that each cross involves two parents.

nMatings <- 10   # we want 10 crosses

contributions$nSlots <- round(2 * nMatings * contributions$Contribution)

contributions
##   Parent Contribution nSlots
## 1  Ind_A         0.25      5
## 2  Ind_B         0.20      4
## 3  Ind_C         0.18      4
## 4  Ind_D         0.15      3
## 5  Ind_E         0.10      2
## 6  Ind_F         0.07      1
## 7  Ind_G         0.03      1
## 8  Ind_H         0.02      0

The column nSlots tells us how many times each parent should appear across all crosses. Then, randomly assign the individual to crosses.

## Mating Plan

##          Parent1 Parent2
## Cross_1    Ind_E   Ind_A
## Cross_2    Ind_A   Ind_D
## Cross_3    Ind_C   Ind_B
## Cross_4    Ind_A   Ind_F
## Cross_5    Ind_A   Ind_D
## Cross_6    Ind_C   Ind_B
## Cross_7    Ind_A   Ind_D
## Cross_8    Ind_G   Ind_C
## Cross_9    Ind_B   Ind_E
## Cross_10   Ind_B   Ind_C

Practice

### -------- Packages and environment -------- ### 
#devtools::install_github("Resende-Lab/SimpleMating")
require(SimpleMating)
require(AGHmatrix)

## 1. Loading the data
data(generic_Geno)
data(generic_IndBLUP)

## 2.Criterion for selection - estimated breeding value
Crit <- data.frame(Id = generic_IndBLUP[, 1],
                   Criterion = generic_IndBLUP[, 2])

## 3. Creating relationship matrix
relMat <- AGHmatrix::Gmatrix(generic_Geno) 

### ——– Optimum contribution Selection ——– ###

#### ------ Focus on genetic gain

## 4. Implementing the algorithm targeting genetic gain
MatePlan_gain <- GOCS(Criterion = Crit, 
                      K = relMat, 
                      nMatings = 30, 
                      Target = "MaxSel", 
                      nProgeny = 1)

# Contributions
sum(MatePlan_gain$Contributions[,2])

# Mating
MatePlan_gain$MatingPlan

#### ------ Focus on Inbreeding

## 5. Implementing the algorithm targeting restriction on inbreeding
MatePlan_inb <- GOCS(Criterion = Crit, 
                 K = relMat, 
                 nMatings = 30, 
                 Target = "MinInb", 
                 nProgeny = 1)

# Contributions
sum(MatePlan_inb$Contributions[,2])

# Mating
MatePlan_inb$MatingPlan


#### ------ Balance between genetic gain and inbreeding

## 6. Implementing the algorithm restricting
MatePlan <- GOCS(Criterion = Crit, 
                     K = relMat, 
                     nMatings = 30, 
                     Target = "both",
                     Degree = 45,
                     nProgeny = 1)

# Contributions
sum(MatePlan$Contributions[,2])

# Mating
MatePlan$MatingPlan

References


  1. University of Florida, ↩︎