Reading
Stories Mode

Designing a Fitness Function

~15 min read Lesson 3 of 4 in Module 13

The fitness function is not a detail of the implementation — it is the problem statement. Getting it wrong is the most common way a genetic algorithm fails.

Fitness Is the Objective

A genetic algorithm has no opinion about your problem. It cannot see the road network, the radio budget or the customer. All it sees is the single number your fitness function returns for each candidate solution, and selection then multiplies whatever earns a high number. That is the entire mechanism. It is also why the fitness function is not a detail of the implementation: it is your problem statement, written in the only language the search can read.

Holland (1975), Adaptation in Natural and Artificial Systems, set out the framework in which selection acts on a population of structures according to a measured payoff, and Goldberg (1989) is the standard textbook treatment that follows it. In both, fitness is the environment: change it and you change what the population becomes. Everything in this lesson follows from that one fact.

The Only Rule the Search Obeys

A genetic algorithm maximises the function you wrote, not the goal you had in mind. Every failure mode in this lesson is a gap between those two things. When a run produces a nonsense winner, suspect the fitness function before you suspect the operators.

Reward the Outcome, Not the Behaviour

The most common way to write a bad fitness function is to picture how you would solve the problem and then score candidates on how closely they imitate you. Suppose you are evolving the duty-cycle schedule of a battery-powered sensor and you want it to run as long as possible while still being useful. It is tempting to reward "keeps the radio switched off", because you know the radio dominates the power budget. Do that and the search will find exactly what you asked for: a schedule with the radio off, a battery that lasts, and no data delivered.

The fix is to measure the outcome you actually care about — useful readings delivered per battery charge — and let the search discover for itself that this implies keeping the radio off most of the time. A fitness function that encodes your assumed method can only ever rediscover your method. One that encodes the outcome is free to find something better.

When the outcome genuinely cannot be measured and you must use a proxy, treat the proxy as a hypothesis rather than as the objective: inspect the winning individual against the real goal by hand before you trust it. Module 14 meets the same hazard from the other direction, where it is called reward hacking — the agent optimises what you measured, not what you meant.

A Worked Example: Placing Sensors

Concretely: you have 40 candidate positions for environmental sensors over a site divided into 200 grid cells. Each position covers a known set of cells and has a known installation cost, and you have a fixed budget. Following Lesson 13.2, a candidate is a binary string of length 40 — bit i is 1 if position i is used.

The obvious first fitness function is "number of distinct cells covered". Run it and the population converges on strings of almost all ones: maximum coverage, and a bill several times the budget. Nothing in that fitness function mentions money, so the search has no reason to care about it. This single example carries the rest of the lesson — it has two objectives in tension, a hard constraint, and an evaluation step that costs real time.

Multi-Objective Problems

Coverage should go up and cost should come down. There is no single best answer to that, only a set of defensible compromises, and the question is which of them the algorithm is allowed to return.

Weighted Sums

The simplest approach collapses the objectives into one number with weights you choose in advance.

Weighted-Sum Fitness
F(\mathbf{x}) = \sum_{i=1}^{m} w_i \, \tilde{f}_i(\mathbf{x}), \qquad w_i \ge 0, \quad \sum_{i=1}^{m} w_i = 1
Each objective is first rescaled to a common range, written here as f-tilde. Skip that step and the weights are effectively decided by your units: cost measured in currency and coverage measured in cells are not comparable numbers, so the objective with the larger raw magnitude silently dominates.

Two honest limitations. First, the weights are a decision you have made before seeing any of the trade-off, and one run returns one compromise. Second, a weighted sum can only ever return solutions that sit on the convex part of the trade-off surface; compromises tucked into a concave stretch of that surface are unreachable by any choice of weights.

Pareto Dominance and the Front

The alternative refuses to collapse the objectives at all. One solution dominates another if it is at least as good on every objective and strictly better on at least one.

Pareto Dominance (all objectives maximised)
\mathbf{a} \succ \mathbf{b} \iff \big(\forall i:\; f_i(\mathbf{a}) \ge f_i(\mathbf{b})\big) \;\wedge\; \big(\exists j:\; f_j(\mathbf{a}) > f_j(\mathbf{b})\big)
Read it as: a is never worse and is somewhere better. Solutions that nothing in the population dominates form the non-dominated set; the true non-dominated set of the whole search space is the Pareto front.

A multi-objective genetic algorithm returns an approximation of that front rather than one point, and a human then picks from it with full sight of what each extra cell of coverage costs. That is usually the more useful deliverable, because the weights were never really known in advance.

NSGA-II in Outline

The standard elitist multi-objective genetic algorithm is NSGA-II, from Deb, Pratap, Agarwal and Meyarivan (2002). Three ideas, and it is worth knowing which is which:

  1. Fast non-dominated sorting — the population is partitioned into fronts. Front 1 is the non-dominated set; front 2 is what becomes non-dominated once front 1 is removed, and so on. A lower front rank is always preferred.
  2. Crowding distance — the tie-breaker within a front, since by definition no member of a front beats another. It estimates how empty the objective space is around each solution, and prefers the ones in sparse regions. This is what keeps the returned front spread out instead of clumped.
  3. Elitism by combination — parents and offspring are pooled, then sorted by front rank and, within a front, by crowding distance, and the pool is truncated back to the population size. A good solution cannot be lost by accident, which is the same argument for elitism made in Lesson 13.2.
ApproachWhat you get backWhen it fitsLimitation
Single objective + penalty One solution One real objective; the others are constraints Needs penalty weights chosen well
Weighted sum One compromise The trade-off is genuinely known in advance Cannot reach concave parts of the trade-off surface
Pareto front (NSGA-II) A spread of compromises A human will choose after seeing the options More machinery; the front still has to be presented and read

Constraint Handling

The budget in the sensor example is not an objective to be traded away — it is a wall. There are four standard ways to teach a genetic algorithm about a wall, and they differ in how much of the search space they leave usable.

Penalised Fitness
F(\mathbf{x}) = f(\mathbf{x}) - \sum_{j=1}^{k} \lambda_j \, \max\!\big(0,\, g_j(\mathbf{x})\big)^{2}
Each constraint is written so that a violation makes g positive, and the penalty grows with the size of the violation. Squaring it means a small overspend costs little and a large one costs a great deal, so the search can still see the direction back toward feasibility.
Penalty
Softens the wall
Subtract a term proportional to the violation. Infeasible individuals stay in the population and can still pass on useful genes.
Rejection
Also called the death penalty
Give any infeasible candidate the worst possible fitness. Simple, but useless when feasible solutions are rare — the search has nothing to climb.
Repair
Fix it, then score it
Turn an infeasible candidate into a nearby feasible one before evaluating — here, drop the least cost-effective sensors until the bill fits.
Feasibility-preserving operators
The wall becomes unreachable
Design crossover and mutation so they cannot produce an invalid child. Order crossover on permutations (Lesson 13.2) is the classic example.

Picking the penalty coefficients is the part that needs judgement. Too small and the winner is an infeasible solution that has simply bought coverage with money it does not have. Too large and the penalty behaves like rejection: the search cannot cross a slightly infeasible ridge to reach a better feasible region on the far side, which is often exactly the path it needs.

Check Feasibility Separately

Always report whether the best individual is feasible as a fact of its own, not as something inferred from its fitness. A penalised score and a genuinely feasible score are the same kind of number, and confusing them is how an infeasible design gets presented as the answer.

Premature Convergence and Diversity Loss

A genetic algorithm's power comes from recombining different solutions. Once the population is made of near-copies of one individual, crossover between two of them produces that same individual again, and mutation is the only remaining source of novelty — which is a very slow random walk. This is premature convergence: the run has stopped improving long before it found anything good, and from the outside it looks exactly like a run that has finished.

How to Detect It

How to Counter It

Diversity is lost when selection pressure is high relative to the variation the operators supply, so every countermeasure adjusts one side of that balance.

Fitness Sharing
f'(i) = \frac{f(i)}{\sum_{j=1}^{P} \mathrm{sh}(d_{ij})}, \qquad \mathrm{sh}(d) = \begin{cases} 1 - (d/\sigma)^{\alpha} & d < \sigma \\ 0 & \text{otherwise} \end{cases}
An individual's fitness is divided by how many neighbours it has within a radius sigma. Ten near-identical copies of a good solution each end up with about a tenth of its fitness, so a lone solution elsewhere can survive alongside them.

Cost Accounting

In almost every real application the fitness evaluation dominates the runtime. Selection, crossover and mutation are a few array operations; one evaluation might be a simulation, a compile-and-test cycle, or the training of a whole model. So the number that matters is not the generation count but the total number of evaluations.

Evaluation Budget
N_{\text{eval}} = P \cdot G, \qquad T_{\text{wall}} \approx \frac{N_{\text{eval}} \cdot t_{\text{eval}}}{K}
P is the population size, G the number of generations, t the cost of one evaluation and K the number of workers. The leading P is the initial population, which is evaluated before any generation runs.

Put arithmetic to it. A population of 100 over 200 generations is 100 × 200 = 20,000 evaluations. At two seconds per evaluation that is 40,000 seconds — a little over eleven hours on one core, or about twenty-one minutes spread across thirty-two workers. Nothing about that is a measurement of any particular problem; it is the multiplication you should do before you start a run rather than after.

Ways to spend the budget better:

Count Before You Run

Decide the evaluation budget first, then choose the population size and generation count to fit inside it. Both matter and they trade off: a large population explores more per generation but affords fewer generations for the same budget. Announcing "we ran 500 generations" says nothing until the reader knows P and the cost of one evaluation.

Key Takeaways

Fitness is the problem statement, so suspect it first when a run misbehaves. Reward the outcome rather than the behaviour you assume produces it. For several objectives, either weight them — after rescaling, and knowing a weighted sum cannot reach concave parts of the trade-off surface — or return a Pareto front, which is what NSGA-II (Deb et al., 2002) does with non-dominated sorting, crowding distance and elitist truncation. Handle constraints by penalty, rejection, repair or feasibility-preserving operators, and always report feasibility separately from fitness. Watch diversity with the best-minus-mean gap and the count of distinct genotypes, and counter its loss by lowering selection pressure, sharing fitness, crowding, restarting or splitting into islands. Finally, budget in evaluations, not generations: the fitness evaluation is where the time goes.

Previous The Genetic Algorithm Loop Overview Next When Evolution Wins — and When It Loses