Development documentation — 0.3.0a4 / main

This is the development branch, not a published stable release. Use the source installation guide. Functional checks cover Ubuntu, Windows and macOS; interpreter, artifact and optional-feature limits still apply. Read support, release gates and known limitations before relying on results.

Run RKO on an instance

Terminal command

After uv sync --locked --group dev, run from the repository root:

uv run --locked python -m examples.run_kp_cpp_instances examples/instances/kp50.txt \
  --limit-time 10 --execution process --random-state 42 \
  --output-csv results/kp50.csv

This is the Knapsack adapter in the repository's examples/ directory (not part of the wheel), analogous to the supplied C++ Problem.h. It reads the instance, constructs RKO, runs the configured portfolio, prints cost/profit/weight/feasibility and exports CSV. Use quotes around paths containing spaces. In PowerShell put the command on one line or replace Bash continuation backslashes with PowerShell backticks.

uv run --locked python -m examples.run_kp_cpp_instances --help lists options. The equivalent installed command is rko-solver ...; running the Python module directly also remains supported. Startup is additional to the process search budget; see README for stopping limits. The packaged default selects ten algorithms. Without --n-jobs, process mode uses at most the smaller of portfolio size and os.process_cpu_count() usable logical CPUs (one if discovery is unavailable). --n-jobs 4 explicitly requests up to four search workers plus the pool manager, even if fewer CPUs are available. Assignments are round-robin; each worker executes its group sequentially. At each dispatch its remaining common-deadline time is shared equally among that worker's remaining searches. Ten algorithms on four workers form groups of 3, 3, 2 and 2: initial shares are approximately one third or one half of the budget, rather than the previous fixed one-third cap for all. Early returns leave more time for the same worker's queued searches; no search receives a new portfolio deadline. Startup remains additional. There is no cross-worker stealing or restart of completed searches; if a worker's final search finishes early, its remaining time is still unused. Callback overruns can consume later searches' slices. This changes timed search trajectories and cooperation, not the configured algorithm selection or seed assignment. Native-library threads are not capped by --n-jobs, and concurrent RKO instances do not share a global worker budget. CPU discovery is affinity-aware, not a guarantee of honoring every container quota; choose an explicit budget when needed. Sequential and thread modes are unchanged. For the historical dedicated-worker behavior with the shipped ten algorithms, use --n-jobs 10. See migration and resource limits. For BLAS-heavy callbacks, native-thread launch settings configure fresh interpreters and their spawned workers without mutating the parent application's native pools.

WSL startup and virtual-environment placement

On WSL, putting .venv under /mnt/c/... also puts NumPy and many Python imports on the Windows-mounted filesystem. Every spawned manager/worker reimports its entry module. For short solves, this can dominate actual search work.

Keep the existing checkout and environment intact while testing an additional Linux-local environment. From the repository root in a WSL shell:

RKO_ENV="$HOME/.cache/rko-python-venv"
UV_PROJECT_ENVIRONMENT="$RKO_ENV" uv sync --locked
UV_PROJECT_ENVIRONMENT="$RKO_ENV" uv run --locked python -m benchmarks.runtime.startup_stages

This remains an editable development installation: dependencies are local to Linux, but Python still reads RKO source and parameter files from the checkout. Keep using the environment prefix on subsequent commands; plain uv run selects the normal project environment again. No global setting or existing .venv needs to be removed. Use a dedicated path for this project, not a shared environment for unrelated repositories.

For installed-package measurements, also place the installed RKO files on Linux:

UV_PROJECT_ENVIRONMENT="$RKO_ENV" uv sync --locked --no-editable
UV_PROJECT_ENVIRONMENT="$RKO_ENV" uv run --locked --no-editable \
  python -m benchmarks.runtime.startup_stages

A non-editable installation is a built package, not a live source view. Do not assume source edits are visible there: rebuild/reinstall for a new artifact, or return to editable development with uv sync --locked using the same environment prefix. Retain --no-editable on installed-package runs so project synchronization does not silently switch the installation mode back.

The identified 18-solve WSL reference reduced end-to-end medians from 5.51–6.17 seconds to 1.56–1.79 seconds by changing installation layout while preserving source bytes and locked versions. That is not a code speedup, a portable latency guarantee or steady-state throughput/quality evidence. Startup remains additional to time_limit, and callback imports/data can add their own cost. Native Windows behavior was not measured by this comparison.

Live progress

The same short command now shows progress automatically:

uv run python -m examples.run_kp_cpp_instances examples/instances/kp50.txt

It prints the engine/portfolio at startup, compact new-best events immediately, and a pool status approximately once per second, even without improvements. For example (illustrative values and timing):

[2026-10-18 15:30:01 +2.103s] NEW BEST algorithm=SA cost=-140 best=-140
[2026-10-18 15:30:02 +3.001s] STATUS best=-140 pool=1/10 [-140 (SA)]
[2026-10-18 15:30:03 +4.001s] STATUS best=-140 pool=1/10 [-140 (SA)]

Timestamps show local wall-clock time and monotonic elapsed solve seconds, including configuration/startup. NEW BEST identifies the producing algorithm and new shared-pool minimum. STATUS shows occupancy/capacity and sorted elite costs with their sources. An initial empty snapshot, and a final snapshot before completion, are also emitted. Chromosomes are not dumped, and full pool contents are not repeated for every insertion.

Search improvements can genuinely cluster within a fraction of a second; records are never delayed or replayed to simulate steady improvement. Periodic status keeps the terminal active during plateaus. It indicates an unfinished portfolio, not proof that callbacks are unblocked or objectives are improving. Rejected and unshared local evaluations are not logged. A successful run ends with RKO DONE; a best evaluation recovered at a budget boundary may not yet have entered the shared pool. Failed runs propagate errors and stop the reporter without a false completion message.

Use --quiet for the previous final-result-only display. Library calls remain silent by default; request the same progress with RKO(..., verbose=True) or legacy run(..., verbose=True). Process output comes from the authoritative pool manager; thread output is protected by the pool lock. The status thread is explicitly stopped and joined when the solve exits, including failures. Lines are flushed immediately, including when stdout is redirected. Output/blocking system scheduling can delay status and affect timed performance; keep library benchmarks quiet.

Your configuration directory

--params-dir selects a directory, not a single file. It must contain config.toml and the selected algorithms' parameter TOMLs. To copy the packaged parameters without depending on source paths, run this once:

uv run --locked python -c "import shutil; from rko_solver.parameters.loader import default_params_dir; shutil.copytree(default_params_dir(), 'configs/my-run', ignore=shutil.ignore_patterns('*.py', '__pycache__'))"

This refuses to overwrite an existing directory. Edit configs/my-run/config.toml, for example:

[run]
control = 1
pool_size = 10

[active_metaheuristics]
list = ["SA", "BRKGA", "GA", "PSO"]

Then run:

uv run --locked python -m examples.run_kp_cpp_instances path/to/instance.txt \
  --params-dir configs/my-run --limit-time 60 \
  --execution process --n-jobs 4 --random-state 42 \
  --output-csv results/my-instance.csv

Each algorithm's .toml contains [offline] scalar values and [online] named value grids. control = 0 selects offline settings; control = 1 enables online control for algorithms that implement it. SA's reference adaptive path remains open compatibility work.

Do not edit installed package files. Do not copy C++ config_tests.conf, ParametersOffline.txt or ParametersOnline.txt directly: their formats are not TOML. C++ strategy, restart, MAXRUNS and debug are not currently supported Python run settings; unsupported keys are rejected, not silently honored. Repeat the command for separate trials. Current constraints are in status.md.

Instance format

The current terminal adapter expects integer Knapsack data: item count and capacity, followed by one profit/weight pair per item, separated by whitespace. For example, an instance with three items and capacity five:

3 5
6 1
10 2
12 3

There is no implicit parsing of arbitrary optimization instances. For a different problem, provide its reader, random-key decoder and objective through the Python RKO class, corresponding to adapting Problem.h in C++. A generic problem-plugin terminal interface is not implemented by this command.

Existing batch selection

Omit the positional instance to run a directory/glob selection:

uv run --locked python -m examples.run_kp_cpp_instances --instances-dir path/to/instances --pattern "kp*.txt" \
  --params-dir configs/my-run --limit-time 60 --n-jobs 4 \
  --output-csv results/batch.csv

A single positional instance cannot be combined with batch selectors. Without any selectors, the kp10.txt and kp50.txt references in examples/instances/ are used. Results are written below the caller's results/ directory unless --output-csv selects a different path. Generated result directories are ignored by Git.