{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Getting Started with OneMax\n", "\n", "This tutorial explains how to implement custom representations, including: (a) one ``Individual``, (b) one ``Variator``, and (c) one ``Evaluator``." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Representation\n", "\n", "To begin, implement a custom representation.\n", "\n", "All custom representations must (a) derive `evokit.core.population.Individual`, (b) store the genotype in `Individual.genome`, and (c) override `Individual.copy`.\n", "\n", "The implementation decides how to create new individuals. Here, the class `BinaryString` implements a factory method `BinaryString.random`, which creates a uniformly random bit string of a certain length." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "from __future__ import annotations\n", "from typing import List, Self\n", "\n", "from random import getrandbits\n", "from evokit.core.population import Individual\n", "\n", "class BinaryString(Individual[List[int]]):\n", " def __init__(self, value: List[int]) -> None:\n", " self.genome: List[int] = value\n", "\n", " @staticmethod\n", " def random(len: int) -> BinaryString:\n", " return BinaryString(\n", " (len * [0] +\n", " [int(digit) for digit in bin(getrandbits(len))[2:]])[-len:]\n", " )\n", "\n", " def copy(self: Self) -> Self:\n", " return type(self)(self.genome.copy())\n", "\n", " def __str__(self: Self) -> str:\n", " return str(self.genome)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Variator\n", "\n", "Implement a custom variator of `BinaryString`. All variators must derive `evokit.core.variator.Variator` and override `Variator.vary`.\n", "\n", "This variator has `.arity=1`, means that it only takes one parent. Consequently, its `.vary` method can expect a tuple of size 1.\n", "\n", "The implementation of `.vary` returns a tuple of size 1. To inform the user of this behaviour, the implementation should set `.coarity=2`." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "from random import random\n", "from typing import Sequence, Tuple\n", "\n", "from evokit.core.variator import Variator\n", "\n", "class RandomBitMutator(Variator[BinaryString]):\n", " def __init__(self, mutation_rate: float):\n", " self.arity = 1\n", " self.coarity = 2\n", " if (mutation_rate < 0 or mutation_rate > 1):\n", " raise ValueError(f\"Mutation rate must be within {0} and {1}.\"\n", " f\"Got: {mutation_rate}\")\n", " self.mutation_rate = mutation_rate\n", "\n", " def vary(self, parents: Sequence[BinaryString]) -> Tuple[BinaryString, ...]:\n", " offspring = parents[0].copy()\n", "\n", " for i in range(0, len(offspring.genome)):\n", " if (random() < self.mutation_rate):\n", " offspring.genome[i] = 1 if offspring.genome[i] == 0 else 1\n", "\n", " return (offspring,)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Evaluator\n", "\n", "Then, implement a custom evaluator of `BinaryString`.\n", "\n", "All custom evaluators must derive `evokit.core.evaluator.Evaluator` and override `Evaluator.evaluate`. Here, `BitDistanceEvaluator` sums all bits in the genotype of a `BinaryString`." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "from evokit.core.evaluator import Evaluator\n", "from typing import override\n", "\n", "class BitDistanceEvaluator(Evaluator[BinaryString]):\n", " @override\n", " def evaluate(self, s1: BinaryString) -> float:\n", " return sum(s1.genome)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Put Everything Together\n", "\n", "Create and run an evolutionary algorithm using components that have already been defined.\n", "\n", "Since selectors and the overall algorithm do not depend on representations, the framework comes with generic ones thatare compatible with all representations.\n", "\n", "Import a selector and an algorithm from `evokit.core.selector` and `evokit.core.algorithm` respectively:\n", "\n", "- Together, `Elitist` and `SimpleSelector` form an elitist selector that always selects for highest-fitness individuals.\n", "- The `SimpleLinearController` applies operators in the following order:\n", "\n", " 1. **evaluate** for selection\n", " 2. **selection**\n", " 3. *update population*\n", " 4. **vary** parents\n", " 5. *update population*" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "from evokit.core.selector import Elitist, SimpleSelector\n", "\n", "from evokit.core.algorithm import SimpleLinearAlgorithm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Initialise Population\n", "\n", "Create a number of `BinaryString` instances, then store them in a `Population`." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "from evokit.core.population import Population\n", "\n", "BINSTRING_LENGTH: int = 1000\n", "POPULATION_SIZE: int = 20\n", "GENERATION_COUNT: int = 100\n", "init_pop = Population[BinaryString]()\n", "\n", "for i in range(0, POPULATION_SIZE):\n", " init_pop.append(BinaryString.random(BINSTRING_LENGTH))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define the Algorithm\n", "\n", "Initialise operators, then run the algorithm with these operators." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "ctrl: SimpleLinearAlgorithm = SimpleLinearAlgorithm(\n", " population=init_pop,\n", " variator=RandomBitMutator(0.1),\n", " selector=Elitist(SimpleSelector[BinaryString](POPULATION_SIZE)),\n", " evaluator = BitDistanceEvaluator()\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Run the Algorithm\n", "\n", "Run the algorithm, then retain the best individual of each generation. Remember to call `copy`, so that subsequent modifications on the individual do not affect the retained copy." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "bests = []\n", "\n", "for _ in range(GENERATION_COUNT):\n", " ctrl.step()\n", " bests.append(ctrl.population[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Analyse Results\n", "\n", "Print best individuals of the first and last generations. Note the that the latter has significantly higher fitness." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Best individual of the first generation is [1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0]\n", " with fitness 579\n", "Best individual of the last generation is [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n", " with fitness 1000\n" ] } ], "source": [ "print(f\"Best individual of the first generation is {bests[0]}\")\n", "print(f\" with fitness {sum(bests[0].genome)}\")\n", "print(f\"Best individual of the last generation is {bests[-1]}\")\n", "print(f\" with fitness {sum(bests[-1].genome)}\")" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from matplotlib import pyplot as plt\n", "plt.title('Training Curve of the Custom Algorithm')\n", "plt.xlabel('Generation')\n", "plt.ylabel('Fitness of Best Individual')\n", "plt.plot([i for i in range(len(bests))], [sum(x.genome) for x in bests])\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 2 }