CEC-2013 LSGO — usage guide¶
Package layout¶
cec2013lsgo/ # repository root (this folder)
├── cec2013lsgo/
│ ├── __init__.py # exports LSGO2013, VALID_FUNC_IDS
│ ├── benchmarks.py # pure-Python F1–F15 (primary API)
│ ├── cdatafiles/ # official F1–F15 data for D=1000
│ ├── cec2013.pyx # legacy Cython binding (optional)
│ └── *.cpp, *.h # original C++ reference implementation
├── tests/
│ ├── test_lsgo2013.py # pure-Python regression tests
│ └── test_bench.py # legacy Cython tests
├── setup.py # optional install (may build Cython extension)
├── README.md
└── docs/
└── usage.md # this guide
Import paths¶
A. Path install (no build)¶
Add the repository root (the directory that contains the inner cec2013lsgo/ package folder) to PYTHONPATH or sys.path:
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent # repository root
sys.path.insert(0, str(ROOT))
from cec2013lsgo import LSGO2013, VALID_FUNC_IDS
Or set the environment once:
export PYTHONPATH="/path/to/cec2013lsgo:${PYTHONPATH}" (Linux/macOS)
$env:PYTHONPATH="C:\path\to\cec2013lsgo;$env:PYTHONPATH" (PowerShell)
B. Editable install¶
From the repository root, run pip install -e ., then:
Class LSGO2013¶
Constructor¶
LSGO2013(
func_id: str, # "cec2013_lsgo_f1" ... "cec2013_lsgo_f15"
D: int, # dimensionality, must be >= 1
seed: int = 0, # instance seed (seed-based path only)
group_size: int = 50, # sub-component size (seed-based path only)
)
| Parameter | Role |
|---|---|
func_id |
Must be in VALID_FUNC_IDS. |
D |
Problem dimension. At D=1000 with bundled cdatafiles/, the official instance is loaded. |
seed |
Fixes shifts, permutations, rotations, and weights when data are generated. Ignored for structure when using_cdatafiles is True. |
group_size |
Target size of rotated groups in seed-based mode (capped at D). |
Evaluation and bounds¶
import numpy as np
bench = LSGO2013("cec2013_lsgo_f4", D=1000, seed=0)
x = np.random.uniform(bench.lb, bench.ub, size=bench.D)
fitness = bench.evaluate(x) # scalar float; x must be shape (D,)
lb = bench.lb_array # np.ndarray (D,)
ub = bench.ub_array # np.ndarray (D,)
lo, hi = bench.bounds # tuple of arrays
print(bench) # shows func_id, D, cdatafiles vs seed
print(bench.using_cdatafiles) # True iff official files were loaded
Scalar bounds bench.lb and bench.ub are the competition box limits for that function (same for every dimension).
Properties¶
| Member | Description |
|---|---|
func_id, D, seed, group_size |
As constructed |
lb, ub |
Scalar search bounds |
lb_array, ub_array |
Per-dimension bound vectors |
using_cdatafiles |
Whether official cdatafiles/ were used |
n_groups |
Number of groups (non-separable types); None for F1–F3, F12, F15 |
Seeds and reproducibility¶
Official benchmark (D = 1000)
a = LSGO2013("cec2013_lsgo_f1", D=1000, seed=0)
b = LSGO2013("cec2013_lsgo_f1", D=1000, seed=999)
# a and b use identical shifts/rotations; seed does not affect structure
Scalable instances (D ≠ 1000 or missing data files)
a = LSGO2013("cec2013_lsgo_f8", D=5000, seed=42)
b = LSGO2013("cec2013_lsgo_f8", D=5000, seed=42)
# same fitness for the same x
c = LSGO2013("cec2013_lsgo_f8", D=5000, seed=43)
# different instance
Tips
- Use one
seedper benchmark instance (shifts, rotations, weights). - Use a separate RNG for your algorithm so
seedonly controls the problem, not the searcher. - Structural data use an isolated
SeedSequencechild stream; passing the same integer toLSGO2013(..., seed=k)and tonumpy.random.default_rng(k)still yields different draws.
Reference values (sanity check)¶
At D = 1000, x = 0, with official cdatafiles/, run pytest tests/test_lsgo2013.py -q from the repository root.
Golden values are pinned in that test file. Most functions agree with the legacy C++/Cython package within floating-point tolerance; F3, F6, and F10 show small differences at (\mathbf{0}) in the pure-Python port.
Examples¶
Loop over all functions¶
import numpy as np
from cec2013lsgo import LSGO2013, VALID_FUNC_IDS
D, seed = 1000, 0
x = np.zeros(D)
for fid in sorted(VALID_FUNC_IDS):
bench = LSGO2013(fid, D=D, seed=seed)
print(fid, bench.evaluate(x))
Arbitrary dimension¶
bench = LSGO2013("cec2013_lsgo_f11", D=2500, seed=7, group_size=50)
x = np.random.default_rng(0).uniform(bench.lb, bench.ub, size=2500)
print(bench.evaluate(x))
Batch evaluation (your own loop)¶
def evaluate_population(bench, X):
"""X: (n, D)"""
return np.array([bench.evaluate(X[i]) for i in range(len(X))])
Minimal optimization loop (illustration)¶
import numpy as np
from cec2013lsgo import LSGO2013
bench = LSGO2013("cec2013_lsgo_f1", D=1000, seed=0)
rng = np.random.default_rng(1) # algorithm RNG, separate from benchmark seed
best_x = rng.uniform(bench.lb, bench.ub, bench.D)
best_f = bench.evaluate(best_x)
for _ in range(1000):
trial = best_x + rng.normal(0, 1, bench.D)
trial = np.clip(trial, bench.lb, bench.ub)
f = bench.evaluate(trial)
if f < best_f:
best_f, best_x = f, trial
print(best_f)
Legacy Cython API (optional)¶
dmolina/cec2013lsgo also ships a Cython binding (F1–F15, D = 1000 only):
from cec2013lsgo.cec2013 import Benchmark
bench = Benchmark()
info = bench.get_info(1) # function index 1..15
fn = bench.get_function(1)
fn(np.zeros(1000))
Build with pip install -e . (g++ and Cython). New code should use LSGO2013 for arbitrary dimension and seed-based instances.
Troubleshooting¶
| Issue | Cause / fix |
|---|---|
Problem not found |
Use cec2013_lsgo_fN strings, not integers N. |
pip install -e . fails on Windows |
Use path install (section A); only NumPy is required for benchmarks.py. |
| Different fitness than papers at D=1000 | Ensure using_cdatafiles is True; evaluate in the stated bounds; use x shape (D,). |
| Slow at large D | Expected; rotation cost grows with group structure. Consider smaller D for debugging. |
Further reading¶
- Competition page: http://goanna.cs.rmit.edu.au/~xiaodong/cec13-lsgo/competition/
- Upstream wrapper: https://github.com/dmolina/cec2013lsgo