Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/c410-f3r/mop

Flexible and modular framework for different NP-Problems with different solvers
https://github.com/c410-f3r/mop

ai framework heuristics metaheuristics np-problem rust solver

Last synced: 17 days ago
JSON representation

Flexible and modular framework for different NP-Problems with different solvers

Awesome Lists containing this project

README

        

# MOP (Many OPtimizations)

[![CI](https://github.com/c410-f3r/mop/workflows/CI/badge.svg)](https://github.com/c410-f3r/mop/actions?query=workflow%3ACI)
[![crates.io](https://img.shields.io/crates/v/mop.svg)](https://crates.io/crates/mop)
[![Documentation](https://docs.rs/mop/badge.svg)](https://docs.rs/mop)
[![License](https://img.shields.io/badge/license-APACHE2-blue.svg)](./LICENSE)
[![Rustc](https://img.shields.io/badge/rustc-1.42-lightgray")](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html)

MOP is a flexible and modular framework for different NP-Problems with different solvers. Through its default pipeline you can define your own custom problem and choose any supported solver combination.

See [this blog post](https://c410-f3r.github.io/thoughts/a-flexible-and-modular-framework-to-solve-np-problems/) for more details or have fun using [the online playground](https://c410-f3r.github.io/mop-playground/).

## Example

The definitions and results of `Binh and Korn`, a multi-objective problem with two hard constraints and two objectives.

![Binh and Korn](https://imgur.com/VDB0oBM.jpg)

###### Picture taken from https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization.

```rust
// Binh T. and Korn U. (1997) MOBES: A Multiobjective Evolution Strategy for Constrained Optimization Problems

use core::cmp::Ordering;
use mop::{
blocks::{
gp::{
mp_defs_from_gp_defs, GpOperations, MpVec, MphDefinitionsBuilder, MphMpMph, MphOrRef, MphVec,
},
objs::MinCstrsRslts,
quality_comparator::ObjsAvg,
ObjDirection, Pct,
},
facades::opt::OptFacade,
solvers::genetic_algorithm::{
operators::{
crossover::MultiPoint, mating_selection::Tournament, mutation::RandomDomainAssignments,
},
GeneticAlgorithmParamsBuilder, Spea2,
},
};

const RSLTS_NUM: usize = 200;

type Solution = [f64; 2];

fn f1(s: &Solution) -> f64 {
4.0 * s[0].powi(2) + 4.0 * s[1].powi(2)
}

fn f2(s: &Solution) -> f64 {
(s[0].powi(2) - 10.0 * s[0] + 25.0) + (s[1].powi(2) - 10.0 * s[1] + 25.0)
}

fn g1(s: &Solution) -> usize {
let lhs = (s[0].powi(2) - 10.0 * s[0] + 25.0) + s[1].powi(2);
match lhs.partial_cmp(&25.0) {
Some(Ordering::Equal) | Some(Ordering::Less) => 0,
_ => 1,
}
}

fn g2(s: &Solution) -> usize {
let lhs = (s[0].powi(2) - 16.0 * s[0] + 64.0) + (s[1].powi(2) + 6.0 * s[1] + 9.0);
match lhs.partial_cmp(&7.7) {
Some(Ordering::Equal) | Some(Ordering::Greater) => 0,
_ => 1,
}
}

fn print_result(result: MphOrRef) {
let solution = result.solution();
let objs = result.obj_rslts();
let hcs = result.hard_cstr_rslts();
println!("x0: {}, x1: {}", solution[0], solution[1]);
println!("f1: {}, f2: {}", objs[0], objs[1]);
println!("g1: {}, g2: {}", hcs[0], hcs[1]);
println!();
}

fn main() -> Result<(), mop::blocks::Error> {
// Problem definitions and results
let mut mph = MphVec::with_capacity(
MphDefinitionsBuilder::default()
.domain([0.0..=5.0, 0.0..=3.0])
.name("Binh and Korn")
.push_hard_cstr(g1 as fn(&Solution) -> usize)
.push_hard_cstr(g2 as fn(&Solution) -> usize)
.push_obj((ObjDirection::Min, f1 as fn(&Solution) -> f64))
.push_obj((ObjDirection::Min, f2 as fn(&Solution) -> f64))
.build()?,
RSLTS_NUM,
);
let (mph_defs, mut mph_rslts) = mph.parts_mut();

// SPEA2 is an unconstrained solver but Binh and Korn is a constrained problem. To workaround
// this incompatibility, our `mph` problem is converted to a `mp` problem by adding an objective
// that minimizes all constraints violations.
//
// It is possible to define your own converstion procedure with any desired set of objectives.
let mcr = MinCstrsRslts::from_gp_hcs(mph_defs);
let mp_defs_ref = mp_defs_from_gp_defs(mph_defs).push_obj((&mcr).into()).build()?;
let mut mp_ref = MpVec::with_random_solutions(mp_defs_ref, 100)?;

// SPEA2 and overall genetic algorithm parameters are specified here.
let spea2 = Spea2::new(
Pct::from_percent(50),
GeneticAlgorithmParamsBuilder::default()
.crossover(MultiPoint::new(1, Pct::from_percent(70)))
.mating_selection(Tournament::new(10, ObjsAvg))
.mutation(RandomDomainAssignments::new(1, Pct::from_percent(30)))
.build()?,
&mp_ref,
RSLTS_NUM,
)?;

// Generic criterias to inspect or stop the solving process.
let of = OptFacade::new(50)
.set_opt_hooks(())
.set_quality_comparator(ObjsAvg)
.set_stagnation(Pct::from_percent(2), 10)?
.solve_problem_with(&mut mp_ref, spea2)
?;

// Transfers all solutions and objectives results of `mp` to `mph`.
MphMpMph::transfer(&mph_defs, &mut mph_rslts, &mp_ref)?;

for (result_idx, result) in mph_rslts.iter().enumerate() {
println!("***** Result #{} *****", result_idx + 1);
print_result(result);
}

if let Some(best_idx) = of.curr_best_idx() {
if let Some(result) = mph.rslts().get(best_idx) {
println!("***** Best result *****");
print_result(result);
}
}

Ok(())
}
```

![Binh and Korn - Objectives](https://imgur.com/VwmLLzP.jpg)

## Solvers

* `SPEA2` (Zitzler and Thiele; SPEA2: Improving the Strength Pareto Evolutionary Algorithm)

## Features

- `no_std` by default
- Different storages (Array, Vec, Slice and more!)
- Fuzz testing
- No `unsafe`

## Optional features

- `std`
- Bindings (wasm-bindgen)
- Parallel evaluation (rayon)
- Deserialization/Serialization (serde)
- Multidimensional storage (ndstruct)