first_60_minutes - morinim/ultra GitHub Wiki

First 60 Minutes with ULTRA

ULTRA is a modern C++ framework for evolutionary computation, including genetic programming, differential evolution, and symbolic regression.

A practical quickstart for newcomers: a successful first run, a tiny custom program, and a clear path for what to learn next.

Goal

In one hour you will:

  1. build ULTRA;
  2. run a built-in example;
  3. write and run your own minimal program;
  4. know where to go next depending on whether you are a user or future contributor.

0) Prerequisites (2 minutes)

You need:

  • a C++23-capable compiler;
  • cmake;
  • Python 3 for some helper tools (optional).

ULTRA is primarily supported on Linux and Windows; other platforms may work but can have rough edges.


1) Get the code (3 minutes)

git clone https://github.com/morinim/ultra.git
cd ultra

2) Configure and build (8 minutes)

Configure:

cmake -B build/ src/

Build:

cmake --build build/

If this completes without errors, your toolchain is working and you are ready to run examples.


3) Run a built-in example (10 minutes)

The easiest first run is the differential evolution example based on the Rastrigin function.

Try one of the following (the path may vary depending on generator/platform):

./build/examples/rastrigin

or, if your generator places binaries at the top-level build directory:

./build/rastrigin

Expected result: optimisation logs followed by a final line reporting a minimum (near zero for a successful run) and the corresponding coordinates.

...
   0.101     380: -1.98952e-13
   0.101     381: -1.63425e-13
   0.102     384: -1.42109e-13
   0.102     385: -1.13687e-13
   0.103     386: -5.68434e-14
   0.104     391: -1.42109e-14
   0.104     393: -7.10543e-15
   0.106     398:           -0
[INFO] Evolution completed at generation: 1002. Elapsed time: 0.241
Run 0 TRAINING. Fitness: -0
Minimum found: -0
Coordinates: [ -5.21528e-10 2.36987e-09 1.52008e-09 2.08037e-10 3.37312e-09 ]

4) Write your first ULTRA program (20 minutes)

Create quickstart_rosen.cc in the repository root:

#include "kernel/ultra.h"

// Rosenbrock minimisation converted to maximisation.
double rosenbrock(const ultra::de::individual &x)
{
  double s = 0.0;

  for (std::size_t i = 0; i + 1 < x.size(); ++i)
  {
    double a = x[i + 1] - x[i] * x[i];
    double b = 1.0 - x[i];
    s += 100.0 * a * a + b * b;
  }

  return -s;
}

int main()
{
  ultra::de::problem prob(3, {-3.0, 3.0});

  prob.params.population.individuals = 40;
  prob.params.evolution.generations = 300;

  ultra::de::search search(prob, rosenbrock);
  auto result = search.run();

  std::cout << "Best fitness: "
            << *result.best_measurements().fitness
            << " at [" << result.best_individual() << "]\n";
}

This program runs a simple optimisation using Differential Evolution. It searches for the point that minimises the Rosenbrock function (ULTRA maximises by default, so the function is negated).

Compile and run it using the library you just built:

c++ -std=c++23 -Isrc quickstart_rosen.cc build/kernel/libultra.a -lpthread -o quickstart_rosen
./quickstart_rosen

If your platform or toolchain needs extra libraries, prefer adding this file under src/examples/ and building via CMake instead.

Population cloud during optimisation (Rosenbrock)


5) Understand the core mental model (10 minutes)

ULTRA usage usually follows this sequence:

  1. define a problem (problem) with domain bounds/data;
  2. set parameters (prob.params...) for population and evolution;
  3. choose a search (de::search, ga::search, src::search...);
  4. run (search.run());
  5. inspect results (best_individual, best_measurements, stats/logs).

If you keep this flow in mind, most examples become easy to read.


6) Common first-hour pitfalls

  • Build succeeds, executable path not found: check where your generator emits binaries (build/examples/ vs build/).
  • Result quality seems poor: increase generations and/or population first.
  • Compiler errors about language features: verify C++23 toolchain.
  • Confusion about objective direction: if you are minimizing, return the negative value (as shown above).

7) What to do next

If you are mainly a user

  • Read and run more examples from src/examples/.
  • Try symbolic regression and classification examples.
  • Start tuning prob.params and compare solution quality and speed.

If you want to contribute

  • Read CONTRIBUTING.md.
  • Learn the structure of src/kernel, src/utility, and src/test.
  • Run tests and explore sanitizer presets in src/CMakePresets.json.
  • Study Software Architecture Document.

8) Optional: install ULTRA

cmake --install build/

This may require elevated privileges depending on your installation prefix.


9) 60-minute checklist

  • Build completed.
  • At least one example executed.
  • Custom minimal program compiled and ran.
  • You can explain the 5-step mental model.
  • You picked a next path (user vs contributor).

If all are checked, you are fully out of "blank page" mode.