use std::fmt::Debug;
use solverforge_core::domain::PlanningSolution;
pub trait SolutionPartitioner<S: PlanningSolution>: Send + Sync + Debug {
fn partition(&self, solution: &S) -> Vec<S>;
fn merge(&self, original: &S, partitions: Vec<S>) -> S;
fn recommended_partition_count(&self) -> Option<usize> {
None
}
}
pub struct FunctionalPartitioner<S, PF, MF>
where
S: PlanningSolution,
PF: Fn(&S) -> Vec<S> + Send + Sync,
MF: Fn(&S, Vec<S>) -> S + Send + Sync,
{
partition_fn: PF,
merge_fn: MF,
recommended_count: Option<usize>,
_phantom: std::marker::PhantomData<fn() -> S>,
}
impl<S, PF, MF> FunctionalPartitioner<S, PF, MF>
where
S: PlanningSolution,
PF: Fn(&S) -> Vec<S> + Send + Sync,
MF: Fn(&S, Vec<S>) -> S + Send + Sync,
{
pub fn new(partition_fn: PF, merge_fn: MF) -> Self {
Self {
partition_fn,
merge_fn,
recommended_count: None,
_phantom: std::marker::PhantomData,
}
}
pub fn with_recommended_count(mut self, count: usize) -> Self {
self.recommended_count = Some(count);
self
}
}
impl<S, PF, MF> Debug for FunctionalPartitioner<S, PF, MF>
where
S: PlanningSolution,
PF: Fn(&S) -> Vec<S> + Send + Sync,
MF: Fn(&S, Vec<S>) -> S + Send + Sync,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FunctionalPartitioner")
.field("recommended_count", &self.recommended_count)
.finish()
}
}
impl<S, PF, MF> SolutionPartitioner<S> for FunctionalPartitioner<S, PF, MF>
where
S: PlanningSolution,
PF: Fn(&S) -> Vec<S> + Send + Sync,
MF: Fn(&S, Vec<S>) -> S + Send + Sync,
{
fn partition(&self, solution: &S) -> Vec<S> {
(self.partition_fn)(solution)
}
fn merge(&self, original: &S, partitions: Vec<S>) -> S {
(self.merge_fn)(original, partitions)
}
fn recommended_partition_count(&self) -> Option<usize> {
self.recommended_count
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ThreadCount {
#[default]
Auto,
Unlimited,
Specific(usize),
}
impl ThreadCount {
pub fn resolve(&self, partition_count: usize) -> usize {
match self {
ThreadCount::Auto => {
let cpus = std::thread::available_parallelism()
.map(|p| p.get())
.unwrap_or(1);
std::cmp::min(cpus, partition_count)
}
ThreadCount::Unlimited => std::thread::available_parallelism()
.map(|p| p.get())
.unwrap_or(1),
ThreadCount::Specific(n) => std::cmp::min(*n, partition_count),
}
}
}
impl std::fmt::Display for ThreadCount {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ThreadCount::Auto => write!(f, "Auto"),
ThreadCount::Unlimited => write!(f, "Unlimited"),
ThreadCount::Specific(n) => write!(f, "{}", n),
}
}
}
#[cfg(test)]
#[path = "partitioner_tests.rs"]
mod tests;