# swarmkit
[](https://crates.io/crates/swarmkit)
[](https://docs.rs/swarmkit)
Composable Particle Swarm Optimization for Rust.
"Kit" because it's a framework for building PSO driven solutions, as opposed to a batteries included approach.
Full API: [docs.rs/swarmkit](https://docs.rs/swarmkit).
## Quick start
```rust
use swarmkit::{Floats, GBestMover, IntoGBestSearcher, ParticleInit, PSOCoeffs, Searcher};
// `Floats<N>` ships with `Add`/`Sub`/`Mul<f64>`/`FieldwiseClamp` and `Index`
// pre-implemented — drop it in as your particle and skip the per-type boilerplate.
type Vec2 = Floats<2>;
let mut searcher = GBestMover::<Vec2>::new(PSOCoeffs::default())
.bounded_by(my_boundary) // your Boundary impl
.into_gbest_searcher(my_fit); // your FitCalc impl
let mut group = my_init.init(&mut rng);
let best = searcher.iter(80, &mut group, None).last().unwrap();
```
Full runnable version at `examples/elliptical.rs` — run it with `cargo run --example elliptical`.
## What you implement
Three traits, regardless of topology:
- `FitCalc` — score a candidate; higher is better.
- `Boundary` — what to do when a particle leaves the search space (typically clamp or reflect).
- `ParticleInit` — seed initial positions and velocities.
For nested PSO, also `ParticleInitDependent` — same shape as `ParticleInit`, but seeds the inner swarm around an outer particle's position.
## Particle type
Any `Copy + Default + Debug + Send + Sync + 'static` type qualifies (the `Unit` marker is auto-implemented for the bound). The PSO mover additionally needs `Add`, `Sub`, `Mul<f64>`; bounded movers need `FieldwiseClamp`.
- Fixed-size numeric vectors: `Floats<N>` has all four pre-implemented. `type MyUnit = Floats<10>;` and go.
- Compound types (e.g. waypoints + times, with sub-unit projection via `ParticleRefFrom`/`SetTo`): implement the four ops on your own newtype.
## Available topologies
- **GBest** — one swarm-wide attractor.
- **LBest** — per-neighbourhood attractors (`Ring { k }` or `VonNeumann`); preserves diversity on multi-basin landscapes.
- **Niched** — static multi-swarm partition; no coordination across niches.
The same mover plugs into all three — switching topology is a one-method-call change:
```rust
mover.into_gbest_searcher(fit);
mover.into_lbest_searcher(fit, LBestKind::Ring { k: 1 });
mover.into_niched_searcher(fit, partition);
```
## Searchers and movers
A `ParticleMover` mutates one particle's position and velocity per iteration. A `Searcher` owns a mover, evaluates fitness, computes whichever per-iteration `Best` its topology defines, and feeds it to the mover. You drive the search by calling `searcher.iter(max_iterations, &mut group, evolution)` and consuming the resulting iterator.
- **`GBestMover`** — the standard PSO velocity update. Works inside any of the three topologies; the searcher decides what `Best` it sees each step.
- **`BoundedMover`** — wraps a mover and applies a `Boundary` after each update. Build via `mover.bounded_by(b)`.
- **`ChainedMover`** — runs two movers in sequence on the same particle, sharing the RNG. Build via `m1.chain(m2)`.
- **`AdapterMover`** — lifts a mover written against a sub-unit (e.g. just the XY of a `Path<N>`) onto the parent unit. Build via `mover.adapt::<ParentCommon>()`.
- **`NestedMover`** — runs an entire inner PSO search inside one outer mover step. Used for nested PSO.
All the combinators stack into a single fluent expression. Pared down from
swarmkit-sailing — an outer spatial PSO with a nested per-segment timing PSO:
```rust
let space = SphericalPSOMover::<N, Path<N>>::new(coeffs) // custom mover (tangent-frame update)
.chain(CauchyKickMover::new(gamma)) // sequence a second mover
.adapt::<Best<Path<N>>>() // lift sub-unit mover onto parent unit
.bounded_by(SailingBoundary::new(/* ... */)); // clamp after each step
let time = time_searcher.nested(8, TimeInit); // an inner PSO, every outer step
let searcher = space.chain(time) // outer + inner movers in sequence
.into_gbest_searcher(fit); // pick a topology
```
## A larger example
[`swarmkit-sailing`](https://github.com/Anvoker/bywind/tree/master/swarmkit-sailing) (in the `bywind` repo) is a substantive use — sailboat route optimization on a spherical Earth. It showcases nested PSO (an outer spatial PSO over route waypoints with a nested per-segment timing PSO inside each outer step) and how to wire a non-trivial physical model into swarmkit.
## License
Licensed under either of
- Apache License, Version 2.0 ([`LICENSE-APACHE`](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([`LICENSE-MIT`](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.