# l_srtde
[](LICENSE)
[](https://www.rust-lang.org/)
A Rust implementation of the L-SRTDE (Large Scale Random Topology Differential
Evolution) algorithm for large-scale numerical optimization.
This crate focuses on large-scale global optimization problems and uses `rayon`
to parallelize population evaluation.
## Reference
This crate implements the algorithm proposed by V. Stanovov and E. Semenkin.
If you use the algorithm or this code in research, cite the original paper:
> V. Stanovov and E. Semenkin, "Success Rate-based Adaptive Differential
> Evolution L-SRTDE for CEC 2024 Competition," 2024 IEEE Congress on
> Evolutionary Computation (CEC), Yokohama, Japan, 2024, pp. 1-8,
> doi: [10.1109/CEC60901.2024.10611907](https://doi.org/10.1109/CEC60901.2024.10611907).
## Features
- Parallel population evaluation with `rayon`
- Success-rate based adaptation of the scaling factor `F`
- Linear population size reduction (LPSR)
- Random-topology strategy for large search spaces
- Pure Rust implementation
- C ABI dynamic library for non-Rust callers
## Installation
```toml
[dependencies]
l_srtde = "0.1.3"
```
## Quick Start
```rust
use l_srtde::{Lsrtde, Problem};
struct SphereProblem {
dim: usize,
}
impl Problem for SphereProblem {
fn dimension(&self) -> usize {
self.dim
}
fn get_bounds(&self, _index: usize) -> (f64, f64) {
(-100.0, 100.0)
}
fn evaluate(&self, genome: &[f64]) -> f64 {
genome.iter().map(|x| x * x).sum()
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let problem = SphereProblem { dim: 100 };
let solver = Lsrtde::new(&problem)
.with_max_evaluations(500_000)
.with_seed(42);
let solution = solver.run()?;
println!("Best Fitness: {:.6e}", solution.fitness);
println!("Best Genome: {:.2?}", solution.genome);
Ok(())
}
```
## Advanced Configuration
```rust
let solver = Lsrtde::new(&problem)
.with_max_evaluations(1_000_000)
.with_pop_size_multiplier(18)
.with_memory_size(5)
.with_seed(12345);
```
You can also use a callback to monitor progress or stop the search early:
```rust
let mut generation = 0;
if generation % 10 == 0 {
println!("Eval: {}, Current Best: {}", evaluations, solution.fitness);
}
true
})?;
```
## C ABI / Dynamic Library
The crate can also be built as a dynamic library for C, C++, Python `ctypes`,
and other languages that can load a C ABI library.
Build the release library:
```bash
cargo build --release
```
The dynamic library is written to `target/release`:
- Windows: `l_srtde.dll`
- Linux: `libl_srtde.so`
- macOS: `libl_srtde.dylib`
Use `include/l_srtde.h` from C:
```c
#include "l_srtde.h"
static int32_t sphere_batch(
const double *points,
size_t point_count,
size_t dim,
double *fitness_out,
void *user_data
) {
(void)user_data;
for (size_t i = 0; i < point_count; ++i) {
double sum = 0.0;
for (size_t j = 0; j < dim; ++j) {
double x = points[i * dim + j];
sum += x * x;
}
fitness_out[i] = sum;
}
return LSRTDE_OK;
}
```
The callback receives a row-major batch of `point_count * dim` doubles and must
write `point_count` fitness values. Return `0` on success and a non-zero value
to stop the optimization with `LSRTDE_CALLBACK_ERROR`.
Example link commands:
```bash
# Linux/macOS
cc main.c -Iinclude -Ltarget/release -ll_srtde -o main
# Windows MSVC
cl main.c /I include target\release\l_srtde.dll.lib
```
Minimal Python `ctypes` loading:
```python
import ctypes
lib = ctypes.CDLL("./l_srtde.dll") # use ./libl_srtde.so or ./libl_srtde.dylib on Unix
lib.lsrtde_minimize.restype = ctypes.c_int32
CALLBACK = ctypes.CFUNCTYPE(
ctypes.c_int32,
ctypes.POINTER(ctypes.c_double),
ctypes.c_size_t,
ctypes.c_size_t,
ctypes.POINTER(ctypes.c_double),
ctypes.c_void_p,
)
@CALLBACK
def sphere(points, point_count, dim, fitness_out, user_data):
for i in range(point_count):
total = 0.0
for j in range(dim):
x = points[i * dim + j]
total += x * x
fitness_out[i] = total
return 0
```
When a C ABI config field is set to zero, `max_evaluations`, `memory_size`, and
`pop_size_multiplier` use the Rust defaults. Set `use_seed` to `0` for a random
seed or non-zero to use `seed`.
## Validation And Budget Semantics
`run()` and `run_with_callback()` now return `Result<_, LsrtdeError>`. The
solver rejects invalid configurations before any parallel evaluation starts.
The current validation rules are:
- `dimension() > 0`
- `memory_size > 0`
- `dimension * pop_size_multiplier` must not overflow
- initial population size must be at least `3`
- every `(lower, upper)` bound pair must be finite and satisfy `lower < upper`
`with_max_evaluations()` is a soft budget, not a hard cap:
- the initial population is always evaluated in full
- each generation evaluates a full batch of trial vectors in parallel
- total objective evaluations can exceed the configured budget
- the overrun is bounded by at most one current-generation population size
## License
This project is licensed under the MIT license. See [LICENSE](LICENSE).