Linear Genetic Programming
Linear genetic programming (LGP) is an evolutionary programming paradigm. It represents the program as a sequence of instructions, where each sequence is either an operation
or a control structure
Exploring the Backstage
[1]:
import evokit.evolvables as evolvables
[2]:
import evokit.evolvables.lgp as lgp
from evokit.evolvables.lgp import cells
[3]:
program = lgp.RegisterStates(registers = (3, 4, 5, 6),
constants = (7, 8, 9, 10, 11))
print(program)
LGP execution context here. Register states:
> r(3, 4, 5, 6), c(7, 8, 9, 10, 11)
[4]:
from evokit.evolvables.primitives import add, sub, mul, div, sin, cos
import random
ASSURANCE_CASE_COUNT = 20
REGISTER_COUNT = 2
CONSTANT_COUNT = 4
registerses = [[random.random() for _ in range(REGISTER_COUNT)] for _ in range(ASSURANCE_CASE_COUNT)]
constantses = [(0., 1., 2., -1.) for _ in range(ASSURANCE_CASE_COUNT)]
def demo_function(registers: list[float], constants: tuple[float,
float,
float,
float]) -> list[float]:
r = registers.copy()
c = constants
r[0] = r[0] * c[1]
r[0] = r[0] + c[1]
if r[1] < c[0]:
r[1] = sin(r[0])
r[1] = r[1] * 5
return r
inputs = list(zip(registerses, constantses))
outputs = [[demo_function(registers, constants)[0]]
for registers, constants in inputs]
[5]:
fitness_cases = list(zip(inputs,
outputs))
Benchmark (just one, need to add more)
[6]:
from evokit.evolvables.lgp import LGPEvaluator, LinearGeneticProgram, Crossover, LGPFactory
from evokit.core import Population
from evokit.evolvables.algorithms import SimpleLinearAlgorithm
from evokit.evolvables.lgp import LGPEvaluator, Crossover
from evokit.evolvables.selectors import TruncationSelector
from typing import Sequence
def maybe_mse(xs: Sequence[float],
ys: Sequence[float]):
return -sum((abs(x - y)**2
for x, y in zip(xs, ys)))
IND_SIZE = 2
POP_SIZE = 40
factora = LGPFactory(
primitives=[add, sub, mul, div, sin, cos],
register_count=REGISTER_COUNT,
constant_count=CONSTANT_COUNT,
)
OUTPUT_INDEX = 1
pop: Population[LinearGeneticProgram] = Population(
[factora.build_fully_effective(segment_length=IND_SIZE,
output_indices={0})
for _ in range(POP_SIZE)]
)
evaluator = LGPEvaluator(fitness_cases=list(fitness_cases),
fitness_function=maybe_mse,
optimise_mode="mask",
output_indices={1},)
variator = Crossover(k=4,
allow_repeat=False,
even=False)
selector = TruncationSelector(budget=POP_SIZE)
algo = SimpleLinearAlgorithm(population=pop,
variator=variator,
evaluator=evaluator,
selector=selector)
[7]:
from typing import Callable
import time
from evokit.watch.watchers import create_fitness_watcher
from evokit.watch.visual import plot
WATCHER_TIMER: Callable[[], float] = time.perf_counter
default_watcher_settings = {
"events": "STEP_END",
"watch_post_step":True,
"timer": WATCHER_TIMER
}
fitness_watcher = create_fitness_watcher(**default_watcher_settings)
algo.register(fitness_watcher)
[8]:
for _ in range(90):
algo.step()
[9]:
algo.population[9].genome
[9]:
[]
[10]:
fitness_watcher[0]
[10]:
WatcherRecord(event='POST_STEP', generation=0, value=(-19.3960483362172,), time=794071.5762742)
[11]:
plot(fitness_watcher, show_generation=True, use_line=True)