๐Ÿค Contributing to TinyverseGP

TinyverseGP is a community project and we warmly welcome contributions of every kind โ€” from new GP representations and problem domains to bug fixes, experiments, and documentation.

Ways to Contribute

TinyverseGP is still in its early stages โ€” every contribution matters. Below are the most impactful areas to get involved in.

๐ŸŒฑ

New GP Representations

Push GP, Stack GP, Gene Expression Programming, Semantic GP, โ€ฆ

๐Ÿ‹๏ธ

New Problem Domains

Time-series forecasting, combinatorial optimisation, multi-objective problems, โ€ฆ

โš™๏ธ

Operators

Crossover, mutation, and selection operators that plug into the existing framework.

๐Ÿ“Š

Benchmarks & Experiments

Replicate published results, add datasets, or run systematic comparisons.

๐Ÿงช

Tests

Unit tests, integration tests, and regression tests to improve reliability.

๐Ÿ“

Documentation

Docstrings, tutorials, Jupyter notebooks, or improvements to this website.

๐Ÿ›

Bug Reports & Fixes

Open a GitHub issue with a minimal reproducer, or directly submit a fix.

๐Ÿ’ก

Feature Requests & Ideas

Start a discussion on GitHub or Discord โ€” we love hearing about new use cases.

Getting Started

1. Fork & clone the repository

# Fork on GitHub first, then:
git clone https://github.com/<your-username>/TinyverseGP.git
cd TinyverseGP
git remote add upstream https://github.com/GPBench/TinyverseGP.git

2. Set up your environment

python3.10 -m venv env
source env/bin/activate   # Windows: env\Scripts\activate
pip install -e .[dev]
โš ๏ธ Python 3.10 required. Versions above 3.10 are currently not supported due to a dependency constraint. Use pyenv if you need to manage multiple Python versions.

3. Create a feature branch

git checkout -b feature/my-awesome-contribution

4. Make your changes, test, and push

# ... make your changes ...

# Run the existing examples to verify nothing is broken
python3 -m examples.symbolic_regression.test_cgp_sr
python3 -m examples.symbolic_regression.test_tgp_sr

# Push and open a Pull Request on GitHub
git push origin feature/my-awesome-contribution

Adding a New GP Representation

All GP representations live in src/gp/ and inherit from GPModel defined in src/gp/tinyverse.py. Follow these steps to add a new one.

Step 1 โ€“ Create the module file

Name your file tiny_<X>gp.py where <X> is the first letter(s) of the representation (e.g., tiny_pgp.py for Push GP). Place it in src/gp/.

Step 2 โ€“ Define Config and Hyperparameters

Create dataclasses that inherit from GPConfig and GPHyperparameters respectively. Add any representation-specific fields.

from dataclasses import dataclass
from src.gp.tinyverse import GPConfig, GPHyperparameters

@dataclass(kw_only=True)
class MyGPConfig(GPConfig):
    # add representation-specific config fields here
    my_param: int = 10

@dataclass(kw_only=True)
class MyGPHyperparameters(GPHyperparameters):
    # add representation-specific hyperparameters here
    my_hp: float = 0.1

Step 3 โ€“ Implement the GPModel subclass

Create a class named Tiny<X>GP (e.g., TinyPGP) that inherits from GPModel and implements all abstract methods:

MethodDescription
init_population() Initialise the population of individuals.
evaluate_individual(genome, problem) Compute and return the fitness of a single genome.
pipeline(problem) Execute one evolutionary generation (selection โ†’ breeding โ†’ evaluation).
selection() Select an individual from the population (e.g., tournament).
predict(genome, observation) Execute a genome on a single input observation and return the output.
expression(genome) Return a human-readable representation of the evolved program.
is_valid(genome) Return True if the genome is a valid program.
eval_complexity(genome) Return a scalar measure of the genome's complexity.
๐Ÿ’ก Look at src/gp/tiny_cgp.py or src/gp/tiny_tgp.py for concrete reference implementations.

Step 4 โ€“ Add an example

Add at least one runnable example in examples/symbolic_regression/ (or another domain) that demonstrates your representation. Update the table in README.md.

Step 5 โ€“ Update Collaborators.md

Add your name and affiliation to Collaborators.md with a short description of your contribution. This is required before your PR can be merged.

Adding a New Problem Domain

Problem domains live in src/benchmark/. The interface is defined in src/gp/problem.py through the abstract Problem class.

Step 1 โ€“ Implement a Problem subclass

Open src/gp/problem.py and add a new class that inherits from Problem. The class must implement three methods:

from src.gp.problem import Problem

class MyProblem(Problem):
    def is_ideal(self, fitness) -> bool:
        """Return True when the optimal fitness has been reached."""
        return fitness == 0.0

    def is_better(self, fitness1, fitness2) -> bool:
        """Return True if fitness1 is strictly better than fitness2."""
        return fitness1 < fitness2

    def evaluate(self, genome, gp_model) -> float:
        """Compute the fitness of genome using gp_model.predict(โ€ฆ)."""
        total_error = 0.0
        for x, y_true in self.data:
            y_pred = gp_model.predict(genome, x)
            total_error += abs(y_pred - y_true)
        return total_error

Step 2 โ€“ Create a benchmark module

Add your benchmark instances in src/benchmark/<domain>/. If you are wrapping an existing benchmark suite, create a thin interface file (see srbench.py or lsbench.py for examples).

Step 3 โ€“ Add examples and update the README

Provide at least one example per representation in examples/<domain>/ and list them in README.md.

Development Workflow

  1. Keep your fork in sync.
    git fetch upstream
    git rebase upstream/main
  2. Write small, focused commits with descriptive messages (Add TinyPGP representation, Fix mutation operator bug in CGP, โ€ฆ).
  3. Open a Pull Request against the main branch of GPBench/TinyverseGP. Fill in the PR template, describing what the change does and how you tested it.
  4. Respond to review feedback promptly. A maintainer will review your PR and may request changes before merging.
  5. Update Collaborators.md in the same PR โ€” this is required before your contribution can be merged.
๐Ÿ  The repository is hosted under the GPBench GitHub Organisation, which is not tied to any single institution. If you want to become a maintainer with write access, please reach out via Discord or by opening a GitHub discussion.

Code Style

  • Follow PEP 8. The existing codebase uses 4-space indentation and type hints wherever practical.
  • Keep each GP representation self-contained in a single file. Avoid adding unnecessary dependencies.
  • Add docstrings to every public class and method, matching the style already used in tinyverse.py.
  • Every file should start with the standard licence header:
    # This file is part of TinyverseGP | https://github.com/GPBench/TinyverseGP
    # License: GPL-3.0-or-later
  • Prefer clarity over cleverness. The main purpose of the codebase is education โ€” readable code is more valuable than micro-optimised code.

Testing

The project uses pytest. Tests live in the tests/ directory. Before submitting a PR, run the full test suite:

pytest tests/

If you are adding a new representation or feature, please add corresponding tests in tests/. At minimum:

  • A smoke test that initialises the model and runs one generation.
  • A test that verifies the predict() and expression() methods return correct types.
  • A regression test if you are fixing a bug.
โš ๏ธ Do not remove or weaken existing tests. If a test needs to change because of your refactoring, explain why in the PR description.

Contact & Community

The best places to ask questions, share ideas, or get feedback before starting a large contribution:

๐Ÿ™ Thank you for taking the time to contribute to TinyverseGP! Every contribution โ€” no matter how small โ€” helps build a better tool for the Genetic Programming community.