evokit.evolvables.lgp package

Module contents

class evokit.evolvables.lgp.Instruction[source]

Bases: ABC, Generic

Base class for all instructions.

An instruction is a “line” in the program.

abstract copy() Self[source]
class evokit.evolvables.lgp.StructureType[source]

Bases: ABC

Base class for all control structure types.

The type of a control structure decides how many times its body is executed: whether once (If), for a number of times (For), or until an expression evaluates to True (While).

Derive this class to create custom structure types.

abstract copy() Self[source]
class evokit.evolvables.lgp.StructureScope[source]

Bases: Instruction

Base class for all control structure scopes.

The scope of a control structure decides how many lines following it become part of its body. The scope also contains a StructureScope, which decides how many times this body is executed.

Derive this class to create custom scopes.

Note

If two scopes are nested, the parent scope limits the size of the child scope. Consider the following example: the parent scope captures and runs the next 5 lines in a “mini context”, so that the next instruction, which would otherwise span 7 lines, ends up spanning only 3 lines.

for ... over 5 lines: >-------+
    <operation>               |
    for ... over 7 lines >--+ |
    <operation>             | |
    <operation> <-----------+ |
    <operation> <-------------+
<operation>
abstract __init__(stype: StructureType, *args: Any, **kwargs: Any) None[source]
Parameters:

stype – Type of the control structure.

abstract scope(instructions: Sequence[Instruction[Any] | None], pos: int) int[source]

Return the actual size of this structure’s scope.

For example, if only 3 instructions exist after the instruction that is supposed to span 5 lines, this method should return 3.

class evokit.evolvables.lgp.StructOverLines[source]

Bases: StructureScope

Control structure that spans a number of lines.

__init__(stype: StructureType, line_count: int) None[source]
Parameters:
  • stype – Type of the control structure.

  • line_count – Number of lines that the control structure spans.

scope(instructions: Sequence[Instruction[Any] | None], pos: int) int[source]
copy() Self[source]
class evokit.evolvables.lgp.StructUntilLabel[source]

Bases: StructureScope

Control structure that extends to and includes the given label.

__init__(stype: StructureType, label: str)[source]
Parameters:
  • stype – Type of the control structure.

  • label – Text of label that terminates this control structure.

scope(instructions: Sequence[Instruction[Any] | None], pos: int) int[source]
copy() Self[source]
class evokit.evolvables.lgp.StructNextLine[source]

Bases: StructOverLines

Control structure that spans one line.

__init__(stype: StructureType)[source]
Parameters:

stype – Type of the control structure.

copy() Self[source]
class evokit.evolvables.lgp.Label[source]

Bases: Instruction, Generic

Text label.

Use with StructUntilLabel.

__init__(text: str)[source]
Parameters:

label – Text of the label.

copy() Self[source]
class evokit.evolvables.lgp.For[source]

Bases: StructureType

“For” loop.

A control structure with this type repeats its body for count times. Not really a for loop, since it does not use a condition.

LOOP_CAP = 20

Maximum number of iterations a For loop can run for.

__init__(count: int | tuple[StateVectorType, int])[source]
count

Number of times the body executes for.

copy() Self[source]
class evokit.evolvables.lgp.While[source]

Bases: StructureType

While loop.

A control structure with this type repeats its body until condition evaluates to True or loop_cap loops have elapsed.

Note

To prevent infinite execution, this structure is a glorified for loop.

LOOP_CAP = 20

Maximum number of iterations a While loop can run for.

__init__(condition: Condition | bool)[source]
Parameters:

condition – Condition that, if satisfied, ends the structures.

condition

Condition that must be satisfied for the structure to stop.

copy() Self[source]
class evokit.evolvables.lgp.If[source]

Bases: StructureType

Structure with condition execution.

A control structure with this type executes once if condition evaluates to True. Otherwise, the structure is skipped and does nothing.

__init__(condition: Condition | bool)[source]
copy() Self[source]
class evokit.evolvables.lgp.StateVectorType[source]

Bases: Enum

Type of a state vector.

A linear program stores two state vectors. Here, RegisterStates.registers are mutable; RegisterStates.constants are immutable.

register = 1
constant = 2
evokit.evolvables.lgp.cell(pos: int) tuple[StateVectorType, int][source]

Convenience function for creating a CellSpecifier.

Arg:
pos: If pos>=0, specify the posth

register. Otherwise, specify the abs(pos)-1 th constant.

evokit.evolvables.lgp.cells(*poses: int) tuple[tuple[StateVectorType, int], ...][source]

Convenience function for creating a tuple of CellSpecifiers.

Arg:

poses: See cell().

class evokit.evolvables.lgp.Operation[source]

Bases: Instruction, Generic

An operation.

Executing this operation calls function with operands as arguments. The result should then be deposited into the targets variable register.

__init__(function: Endofunction[R], target: int, operands: tuple[CellSpecifier, ...] | list[CellSpecifier])[source]
Parameters:
  • function – A function.

  • target – A position in the variable register.

  • operands – Arguments to function.

copy() Self[source]
class evokit.evolvables.lgp.Condition[source]

Bases: Generic

Base class for predicates, or conditions.

Conditions are used by condition control structures, such as If and While.

__init__(function: Predicate[R], args: Sequence[CellSpecifier])[source]
Parameters:
  • function – A predicate

  • args – Arguments to function

class evokit.evolvables.lgp.RegisterStates[source]

Bases: Generic

Context for executing linear programs.

A context stores states of a program. These states include constant and variable registers. Call methods of the context to run instructions in this state.

This context is generic, and as such works with all endofunctions in its type argument [1].

__init__(registers: list[R], constants: tuple[R, ...], verbose: bool = False)[source]
Parameters:
  • registers – Variable registers, registers for short.

  • constants – Constant registers. Someone once called these constants and I wholeheartedly agree with that.

  • verbose – If True, then evaluating each operation or condition also prints to STDOUT.

registers: list[R]

The register vector stores mutable state variables. Set with set_register().

constants: tuple[R, ...]

The constant vector stores immutable state variables. Set with set_constants().

verbose

If True, then each operation also prints what it does.

set_registers(registers: list[R]) None[source]

Set the register vector to registers.

set_constants(constants: tuple[R, ...]) None[source]

Set the constant vector to constants.

get_cell_value(spec: CellSpecifier) R[source]

Return the value in the cell specified by spec.

get_state_vector(celltype: StateVectorType) Sequence[R][source]

Return the state vector specified by celltype.

run(instructions: Sequence[Instruction | None]) None[source]

Execute instructions in this context.

Parameters:

instructions – A sequence of instructions to run. Items that are None are skipped.

Effect:

Executing an Operation updates registers.

check_condition(cond: Condition) bool[source]

Execute a condition in the current context, return the result.

copy() Self[source]
evokit.evolvables.lgp.check_all(verbose: bool = False) bool[source]
class evokit.evolvables.lgp.LGPFactory[source]

Bases: Generic[R]

Convenience factory class that creates linear programs.

Supports a plethora of settings that fine-tune the initialisation process.

__init__(primitives: Sequence[Primitive[R]], register_count: int, constant_count: int, override_structure_types: tuple[Type[StructureType]] | None = None, *, structure_size: int | Callable[[], int] = 5, for_count: int | Callable[[], int] = 5, for_count_constant_ratio: float = 5, allow_replacement: bool = True, allow_constant_conditions: bool = False, allow_constant_operations: bool = False, override_primitive_weights: Sequence[float] | None = None, override_logical_operators: set[Predicate] | None = None)[source]
Parameters:
  • primitives

    Building blocks for the program. Each primitive may be selected to form an instruction.

    If 2-tuples (primitive, weight) are given, then each primitive is selected with the given weight.

  • register_count – Number of variable registers available.

  • constant_count – Number of constant registers available.

  • override_structure_types

    Control structure types that may be used to complete control structures.

    A control structure consists of two parts: a StructureScope decides its scope and StructureType decides its behaviour (e.g. if it is a For or While loop.

    If a StructureScope is selected from primitives, then one of structure_types is selected to populate it.

  • structure_size

    The allowed size of the structure. Can be an int or a callable that returns an int.

    • If structure_size is an int: uniformly draw an integer from [0, 1, …, structure_size].

    • If structure_size is callable, then call it and use the returned value.

  • for_count – The loop count for for loop. Can be an int or a callable that returns an int. See structure_size for details.

  • for_count_constant_ratio – Experimental feature that doesn’t exist in the original paper. Possibility that a for loop runs for a fixed number of times (i.e. for for_count to be used). If not a constant, the count will be taken from a register when the for instruction is encountered. Set to 1 to disable.

  • register_count – Number of variable registers used by the program.

  • constant_count – Number of constant registers used by the program.

  • allow_replacement – If True, then registers are drawn with replacement.

  • allow_constant_conditions – If True, then If and While loops can have constant conditions. Such loops either always or never execute.

  • allow_constant_operations – If True, then Operations can have constants as all arguments. Several texts call this a bad idea.

  • override_logical_operators – Logical operators that may be used by conditions. By default, all logical operators in primitives are used.

logical_operators: set[Predicate]

Logical operators that may be drawn to form conditions.

build(length: int) LinearGeneticProgram[source]

Build and return a sequence of instructions to the given length.

build_fully_effective(segment_length: int, output_indices: set[int], target_length: int | None = None) LinearGeneticProgram[source]

Build and return a sequence of effective instructions. Do so by building sequences of segment_length instructions, then removing introns from the result.

If a target_length is given, then build a new sequence and append it to the previous one until the accumulated sequence meets or exceeds target_length. May produce longer sequences as a result.

class evokit.evolvables.lgp.LGPEvaluator[source]

Bases: Evaluator[LinearGeneticProgram], Generic

__init__(fitness_cases: Sequence[FitnessCase], output_indices: set[int], optimise_mode: Literal['none', 'mask', 'reduce'], fitness_function: Callable[[Sequence, Sequence], float], verbose=False, processes: int | ProcessPoolExecutor | None = None, share_self: bool = False) None[source]
Parameters:
evaluate(individual: LinearGeneticProgram) tuple[float, ...][source]

This class overrides evaluate_population instead.

class evokit.evolvables.lgp.LinearGeneticProgram[source]

Bases: Individual[Sequence[Instruction]], Generic

A Linear genetic program. This program consists of a sequence of instructions, which in turn act on registers.

Not to be confused with LGP, which means linear genetic programming.

__init__(program: Sequence[Instruction])[source]
copy() Self[source]
class evokit.evolvables.lgp.Crossover[source]

Bases: Variator[LinearGeneticProgram]

Cross over two sequences. Can cross over at any number (k) of points. Can produce offspring that have different lengths.

__init__(k: int, allow_repeat: bool = True, even: bool = True) None[source]
Parameters:
  • k – The number of crossover points.

  • allow_repeat – If True, then crossover segments can be empty. Swapping any segment with an empty segment effectively moves it to the empty segment’s index.

  • even – If True, then crossover segments must have the same size and each offspring has the same size as its “direct” parent (parent where the offspring takes its first segment from). Otherwise, offspring can have different lengths.

vary(parents: Sequence[LinearGeneticProgram]) tuple[LinearGeneticProgram, LinearGeneticProgram][source]

Required.

Produce new individuals from existing ones.

Because .arity=1 in the initialiser, parents will be a 1-tuple at runtime.