The GA and the function
Lax343628.Algorithm · concepts/Lax343628/Algorithm.lean · lax-343628
No public endorsements yet.
Loading review…
Sign in with ORCIDNatural Language Statement
Definition
For , let be its number of ones. For a jump size , the function is
The genetic algorithm with crossover probability maintains a population, a multiset of individuals from . One iteration, maximizing a fitness function , proceeds as follows:
- With probability , choose two parents uniformly at random with replacement from the population. Create the offspring by uniform crossover of and , which takes each bit from or independently with probability , followed by standard bit mutation, which flips each bit independently with probability .
- Otherwise, choose a parent uniformly at random and create by standard bit mutation of .
- Add to the population and remove an individual with the lowest fitness, breaking ties uniformly at random.
Concept map
Lean source view on GitHub
| 1 | import Mathlib.Data.PNat.Basic |
| 2 | import Mathlib.Probability.Distributions.Uniform |
| 3 | import Mathlib.Probability.ProbabilityMassFunction.Constructions |
| 4 | |
| 5 | /-! |
| 6 | --- |
| 7 | title: The GA and the function |
| 8 | type: definition |
| 9 | --- |
| 10 | For , let be its number of ones. For a jump size , |
| 11 | the function is |
| 12 | |
| 13 | |
| 14 | |
| 15 | The genetic algorithm with crossover probability maintains a |
| 16 | population, a multiset of individuals from . One iteration, maximizing a |
| 17 | fitness function , proceeds as follows: |
| 18 | |
| 19 | 1. With probability , choose two parents uniformly at random with replacement from |
| 20 | the population. Create the offspring by uniform crossover of and , which takes |
| 21 | each bit from or independently with probability , followed by standard bit |
| 22 | mutation, which flips each bit independently with probability . |
| 23 | 2. Otherwise, choose a parent uniformly at random and create by standard bit mutation |
| 24 | of . |
| 25 | 3. Add to the population and remove an individual with the lowest fitness, breaking ties |
| 26 | uniformly at random. |
| 27 | -/ |
| 28 | |
| 29 | namespace Lax343628.Algorithm |
| 30 | |
| 31 | open scoped ENNReal Classical BigOperators |
| 32 | |
| 33 | noncomputable section |
| 34 | |
| 35 | /-- A string in . `Fin n` indexes positions ; |
| 36 | `Fin 2` consists of the values zero and one. -/ |
| 37 | abbrev BitString (n : ℕ) := Fin n → Fin 2 |
| 38 | |
| 39 | /-- A population of positive size , with entries indexed separately even when equal. |
| 40 | An iteration writes the offspring into the slot of the deleted entry, or discards it if it |
| 41 | is deleted itself; up to the order of entries, this is adding it and then deleting. -/ |
| 42 | abbrev Population (n : ℕ) (μ : ℕ+) := Fin (μ : ℕ) → BitString n |
| 43 | |
| 44 | /-- The number of one-bits in a string. -/ |
| 45 | def ones {n : ℕ} (x : BitString n) : ℕ := |
| 46 | ∑ j : Fin n, (x j : ℕ) |
| 47 | |
| 48 | /-- The function with jump size `k`, usually considered for and |
| 49 | . Fitness values are real numbers; natural-number subtraction is truncated |
| 50 | at zero. -/ |
| 51 | def jump {n : ℕ} (k : ℕ) (x : BitString n) : ℝ := |
| 52 | if ones x ≤ n - k ∨ ones x = n then (k + ones x : ℕ) else (n - ones x : ℕ) |
| 53 | |
| 54 | /-- The all-one string , the unique optimum of when . -/ |
| 55 | def optimum (n : ℕ) : BitString n := fun _ ↦ 1 |
| 56 | |
| 57 | /-- A Bernoulli bit, equal to one with probability for . |
| 58 | Outside this interval it always returns the bit 0; all algorithm claims use valid probabilities. -/ |
| 59 | def coin (p : ℝ) : PMF (Fin 2) := |
| 60 | if h : 0 ≤ p ∧ p ≤ 1 then |
| 61 | PMF.ofFintype (fun b : Fin 2 ↦ ENNReal.ofReal (if b = 1 then p else 1 - p)) |
| 62 | -- Lean checks this proof that the probabilities sum to one; readers can skip it. |
| 63 | (by simp_all [Fin.sum_univ_two, ← ENNReal.ofReal_add]) |
| 64 | else PMF.pure 0 |
| 65 | |
| 66 | /-- Independent Bernoulli bits, each equal to one with probability : a string has |
| 67 | probability , which is for |
| 68 | . Here `coin p b` is the probability that the coin shows the bit `b`. -/ |
| 69 | def independentBits (n : ℕ) (p : ℝ) : PMF (BitString n) := |
| 70 | PMF.ofFintype (fun x ↦ ∏ j, coin p (x j)) |
| 71 | -- Lean checks this proof that the probabilities sum to one; readers can skip it. |
| 72 | (by |
| 73 | have h := (coin p).tsum_coe |
| 74 | rw [tsum_fintype] at h |
| 75 | rw [← Fintype.prod_sum] |
| 76 | simp [h]) |
| 77 | |
| 78 | /-- Uniform crossover: at each position an independent fair mask bit selects one parent. |
| 79 | Sampling the mask uniformly among all bit strings gives independent fair choices. -/ |
| 80 | def crossover {n : ℕ} (x y mask : BitString n) : BitString n := |
| 81 | fun j ↦ if mask j = 1 then x j else y j |
| 82 | |
| 83 | /-- Flip exactly the positions where the mutation mask is one. -/ |
| 84 | def mutate {n : ℕ} (x mask : BitString n) : BitString n := |
| 85 | fun j ↦ if mask j = 1 then 1 - x j else x j |
| 86 | |
| 87 | /-- Uniform deletion among the entries of minimal `fitness`, including the offspring. |
| 88 | The minimum exists because the enlarged population is finite and nonempty. -/ |
| 89 | def deletionIndex {n : ℕ} (fitness : BitString n → ℝ) {μ : ℕ+} |
| 90 | (Q : Fin ((μ : ℕ) + 1) → BitString n) : PMF (Fin ((μ : ℕ) + 1)) := |
| 91 | PMF.uniformOfFinset |
| 92 | (Finset.univ.filter fun i ↦ ∀ j, fitness (Q i) ≤ fitness (Q j)) |
| 93 | -- Lean checks this proof that a minimal entry exists; readers can skip it. |
| 94 | (by simpa [Finset.filter_nonempty_iff] using Finite.exists_min fun j ↦ fitness (Q j)) |
| 95 | |
| 96 | /-- One iteration of the GA, maximizing `fitness`. |
| 97 | Crossover parents are independent uniform draws with replacement; the mutation-only |
| 98 | parent is uniform. Mutation flips each bit independently with probability . |
| 99 | The offspring is inserted even if it equals an existing entry, before a worst entry is deleted. |
| 100 | Each `←` draws a sample from the distribution on its right. -/ |
| 101 | def step {n : ℕ} (fitness : BitString n → ℝ) {μ : ℕ+} (p_c : ℝ) (P : Population n μ) : |
| 102 | PMF (Population n μ) := do |
| 103 | let useCrossover ← coin p_c |
| 104 | -- `z'` is the uniform crossover of the parents `P u` and `P v`, or the parent `P u` itself. |
| 105 | let z' ← if useCrossover = 1 then do |
| 106 | let (u, v) ← PMF.uniformOfFintype (Fin (μ : ℕ) × Fin (μ : ℕ)) |
| 107 | let crossMask ← PMF.uniformOfFintype (BitString n) |
| 108 | pure (crossover (P u) (P v) crossMask) |
| 109 | else do |
| 110 | let u ← PMF.uniformOfFintype (Fin (μ : ℕ)) |
| 111 | pure (P u) |
| 112 | let flipMask ← independentBits n (1 / (n : ℝ)) |
| 113 | let z := mutate z' flipMask |
| 114 | -- `Q` lists the μ + 1 entries: the population `P`, followed by the offspring `z`. |
| 115 | let Q := Fin.lastCases z P |
| 116 | let d ← deletionIndex fitness Q |
| 117 | -- Deleting an old entry puts z into its slot; deleting the offspring (the last entry of |
| 118 | -- `Q`) leaves P unchanged. |
| 119 | pure (if h : d.val < (μ : ℕ) then Function.update P ⟨d.val, h⟩ z else P) |
| 120 | |
| 121 | end |
| 122 | end Lax343628.Algorithm |
| 123 |
Discussion
Ask a question or add context. Endorsements and structured flags are kept in the review panel above.
0 comments