An open API service indexing awesome lists of open source software.

https://github.com/germanheim/globalsearch-rs

Global optimization with scatter search and local NLP solvers written in Rust
https://github.com/germanheim/globalsearch-rs

math numerical-optimization optimization optimization-algorithms rust scatter-search

Last synced: about 1 year ago
JSON representation

Global optimization with scatter search and local NLP solvers written in Rust

Awesome Lists containing this project

README

          


GlobalSearch-rs


Global optimization with scatter search and local NLP solvers written in Rust



Docs | Examples



crates version


CI


Codecov


MIT License

`globalsearch-rs`: Rust implementation of the _OQNLP_ (_OptQuest/NLP_) algorithm with the core ideas from "Scatter Search and Local NLP Solvers: A Multistart Framework for Global Optimization" by Ugray et al. (2007). It combines scatter search metaheuristics with local minimization for global optimization of nonlinear problems.

Similar to MATLAB's `GlobalSearch` \[2\], using argmin, rayon and ndarray.

## Features

- 🐍 [Python Bindings](https://github.com/GermanHeim/globalsearch-rs/tree/main/python)

- 🎯 Multistart heuristic framework for global optimization

- πŸ“¦ Local optimization using the argmin crate \[3\]

- πŸš€ Parallel execution of initial stage using Rayon

## Installation

### Using as a dependency

Add this to your `Cargo.toml`:

```toml
[dependencies]
globalsearch = "0.2.0"
```

Or use `cargo add globalsearch` in your project directory.

### Building from source

1. Install Rust toolchain using [rustup](https://rustup.rs/).
2. Clone repository:

```bash
git clone https://github.com/GermanHeim/globalsearch-rs.git
cd globalsearch-rs
```

3. Build the project:

```bash
cargo build --release
```

## Usage

1. Define a problem by implementing the `Problem` trait.

```rust
use ndarray::{array, Array1, Array2};
use globalsearch::problem::Problem;
use globalsearch::types::EvaluationError;

pub struct MinimizeProblem;
impl Problem for MinimizeProblem {
fn objective(&self, x: &Array1) -> Result {
Ok(
..., // Your objective function here
)
}

fn gradient(&self, x: &Array1) -> Result, EvaluationError> {
Ok(array![
..., // Optional: Gradient of your objective function here
])
}

fn hessian(&self, x: &Array1) -> Result, EvaluationError> {
Ok(array![
..., // Optional: Hessian of your objective function here
])
}

fn variable_bounds(&self) -> Array2 {
array![[..., ...], [..., ...]] // Lower and upper bounds for each variable
}
}
```

Where the `Problem` trait is defined as:

```rust
pub trait Problem {
fn objective(&self, x: &Array1) -> Result;
fn gradient(&self, x: &Array1) -> Result, EvaluationError>;
fn hessian(&self, x: &Array1) -> Result, EvaluationError>;
fn variable_bounds(&self) -> Array2;
}
```

Depending on your choice of local solver, you might need to implement the `gradient` and `hessian` methods. Learn more about the local solver configuration in the [argmin docs](https://docs.rs/argmin/latest/argmin/solver/index.html) or the [`LocalSolverType`](https://docs.rs/globalsearch/latest/globalsearch/types/enum.LocalSolverType.html).

> πŸ”΄ **Note:** Variable bounds are only used in the scatter search phase of the algorithm. The local solver is unconstrained (See [argmin issue #137](https://github.com/argmin-rs/argmin/issues/137)) and therefor can return solutions out of bounds.

2. Set OQNLP parameters

```rust
use globalsearch::types::{LocalSolverType, OQNLPParams};
use globalsearch::local_solver::builders::SteepestDescentBuilder;

let params: OQNLPParams = OQNLPParams {
iterations: 125,
wait_cycle: 10,
threshold_factor: 0.2,
distance_factor: 0.75,
population_size: 250,
local_solver_type: LocalSolverType::SteepestDescent,
local_solver_config: SteepestDescentBuilder::default().build(),
seed: 0,
};
```

Where `OQNLPParams` is defined as:

```rust
pub struct OQNLPParams {
pub iterations: usize,
pub wait_cycle: usize,
pub threshold_factor: f64,
pub distance_factor: f64,
pub population_size: usize,
pub local_solver_type: LocalSolverType,
pub local_solver_config: LocalSolverConfig,
pub seed: u64,
}
```

And `LocalSolverType` is defined as:

```rust
pub enum LocalSolverType {
LBFGS,
NelderMead,
SteepestDescent,
TrustRegion,
NewtonCG,
}
```

You can also modify the local solver configuration for each type of local solver. See [`builders.rs`](https://github.com/GermanHeim/globalsearch-rs/tree/main/src/local_solver/builders.rs) for more details.

3. Run the optimizer

```rust
use oqnlp::{OQNLP, OQNLPParams};
use types::{SolutionSet}

fn main() -> Result<(), Box> {
let problem = MinimizeProblem;
let params: OQNLPParams = OQNLPParams {
iterations: 125,
wait_cycle: 10,
threshold_factor: 0.2,
distance_factor: 0.75,
population_size: 250,
local_solver_type: LocalSolverType::SteepestDescent,
local_solver_config: SteepestDescentBuilder::default().build(),
seed: 0,
};

let mut optimizer: OQNLP = OQNLP::new(problem, params)?;

// OQNLP returns a solution set with the best solutions found
let solution_set: SolutionSet = optimizer.run()?;
println!("{}", solution_set)

Ok(())
}
```

## Project Structure

```plaintext
src/
β”œβ”€β”€ lib.rs # Module declarations
β”œβ”€β”€ oqnlp.rs # Core OQNLP algorithm implementation
β”œβ”€β”€ scatter_search.rs # Scatter search component
β”œβ”€β”€ local_solver/
β”‚ β”œβ”€β”€ builders.rs # Local solver configuration builders
β”‚ └── runner.rs # Local solver runner
β”œβ”€β”€ filters.rs # Merit and distance filtering logic
β”œβ”€β”€ problem.rs # Problem trait
└── types.rs # Data structures and parameters
python/ # Python bindings
```

## Dependencies

- [argmin](https://github.com/argmin-rs/argmin)
- [ndarray](https://github.com/rust-ndarray/ndarray)
- [rayon](https://github.com/rayon-rs/rayon) [feature: `rayon`]
- [kdam](https://github.com/clitic/kdam) [feature: `progress_bar`]
- [rand](https://github.com/rust-random/rand)
- [thiserror](https://github.com/dtolnay/thiserror)
- [criterion.rs](https://github.com/bheisler/criterion.rs) [dev-dependency]

## License

Distributed under the MIT License. See [`LICENSE.txt`](https://github.com/GermanHeim/globalsearch-rs/blob/main/LICENSE.txt) for more information.

## References

\[1\] Zsolt Ugray, Leon Lasdon, John Plummer, Fred Glover, James Kelly, Rafael MartΓ­, (2007) Scatter Search and Local NLP Solvers: A Multistart Framework for Global Optimization. INFORMS Journal on Computing 19(3):328-340.

\[2\] GlobalSearch. The MathWorks, Inc. Available at: (Accessed: 27 January 2025)

\[3\] Kroboth, S. argmin{}. Available at: (Accessed: 25 January 2025)