diff --git a/examples/benchmark.rs b/examples/benchmark.rs index 16c88c3..df0313b 100644 --- a/examples/benchmark.rs +++ b/examples/benchmark.rs @@ -11,7 +11,7 @@ use std::{fs::OpenOptions, time::SystemTime}; use fnv::FnvHashMap; use rmf_reservations::algorithms::greedy_solver::ConflictTracker; -use rmf_reservations::algorithms::sat::{generate_sat_devil, SATSolver}; +use rmf_reservations::algorithms::sat::{generate_sat_devil, FixedTimeSATSolver}; use rmf_reservations::discretization; fn main() { @@ -29,18 +29,18 @@ fn main() { let timer = SystemTime::now(); - SATSolver::without_optimality_check(soln.clone()); + FixedTimeSATSolver::without_optimality_check(soln.clone()); let optimality_proof_dur = timer.elapsed(); let timer = SystemTime::now(); - SATSolver::from_hill_climber(soln.clone()); + FixedTimeSATSolver::from_hill_climber(soln.clone()); let brute_force_proof_dur = timer.elapsed(); let hint = FnvHashMap::default(); let timer = SystemTime::now(); let stop = Arc::new(AtomicBool::new(false)); - soln.solve(hint, stop); + soln.naive_greedy_solver(hint, stop); let greedy_dur = timer.elapsed(); println!( diff --git a/examples/discrete_vs_nodiscrete.rs b/examples/discrete_vs_nodiscrete.rs index e124b59..2d1f4e5 100644 --- a/examples/discrete_vs_nodiscrete.rs +++ b/examples/discrete_vs_nodiscrete.rs @@ -10,7 +10,7 @@ use chrono::TimeZone; use chrono::Utc; use rmf_reservations::algorithms::greedy_solver::ConflictTracker; use rmf_reservations::algorithms::greedy_solver::Problem; -use rmf_reservations::algorithms::sat::{generate_sat_devil, SATSolver}; +use rmf_reservations::algorithms::sat::{generate_sat_devil, FixedTimeSATSolver}; use rmf_reservations::algorithms::sat_flexible_time_model; use rmf_reservations::algorithms::sat_flexible_time_model::SATFlexibleTimeModel; use rmf_reservations::cost_function::static_cost::StaticCost; @@ -105,7 +105,7 @@ fn main() { let soln = system.generate_literals_and_remap_requests(); let timer = SystemTime::now(); - SATSolver::without_optimality_check(soln.clone()); + FixedTimeSATSolver::without_optimality_check(soln.clone()); let optimality_proof_dur = timer.elapsed(); let sat_flexible_time_problem = sat_flexible_time_model::Problem { requests }; diff --git a/readme.md b/readme.md index 8ab261d..13764c8 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # RMF Reservations -This is a library that provides resource optimization constraints for multi-robot applications. More specifcally, +This is a library that provides a solver for constrained resource scheduling for multi-robot applications. More specifically, we provide a very simple formulation for resource optimization and scheduling. A robot may request the use of a resource like a charger for a fixed duration of time within a given time range. The system will then assign the robot to said resource. @@ -36,9 +36,9 @@ Alternatives: - Cost: My own cost function ``` -The requests can come in asynchronously. We can solve both optimally and suboptimally depoending on the complexity of the problem. +The requests can come in asynchronously. We can solve both optimally and sub-optimally depending on the complexity of the problem. -A variety of algorithms have been implmented in this library including SAT based algorithms and greedy algorithms. +A variety of algorithms have been implemented in this library including SAT based algorithms and greedy algorithms. For more details take a look at the tutorial: diff --git a/src/algorithms/greedy_solver.rs b/src/algorithms/greedy_solver.rs index d6fef08..68e3c0c 100644 --- a/src/algorithms/greedy_solver.rs +++ b/src/algorithms/greedy_solver.rs @@ -529,8 +529,9 @@ impl Problem { conflicts } - /// Check conflict by remapping timelines - pub fn solve( + /// This solves reservation related problems by using a very simple greedy algorithm. + /// Only use this if the problem has an obvious solution. + pub fn naive_greedy_solver( &self, hint: HashMap, stop: Arc, @@ -592,22 +593,6 @@ impl Problem { positive_constraints.insert(req_id, alt); - // Check starvation sets - /* let starved: bool = { - let mut val = false; - for starvation_group in &starvation_sets { - let mut hashset = FnvHashSet::from_iter(positive_constraints.iter().map(|(k,v)| (*k, *v))); - if hashset.intersection(&starvation_group.positive).count() == starvation_group.positive.len() { - val =true; - } - } - val - }; - if starved { - println!("Dropping solution cause it will starve resources"); - continue; - }*/ - if let Some(banned_resources) = implications.get(&(req_id, alt)) { negative_constraints.extend( banned_resources @@ -717,7 +702,7 @@ fn test_conflict_checker() { //println!("Generated literals"); solver.debug_print(); let stop = Arc::new(AtomicBool::new(false)); - let (solution, _) = solver.solve(FnvHashMap::default(), stop).unwrap(); + let (solution, _) = solver.naive_greedy_solver(FnvHashMap::default(), stop).unwrap(); println!("{:?}", solution); assert!((solution.cost.0 - 8.0).abs() < 1.0); } @@ -742,7 +727,7 @@ fn test_generation() { let soln = system.generate_literals_and_remap_requests(); soln.debug_print(); let arc = Arc::new(AtomicBool::new(false)); - let _ = soln.solve(FnvHashMap::default(), arc).unwrap(); + let _ = soln.naive_greedy_solver(FnvHashMap::default(), arc).unwrap(); // Ok(()) //}); } @@ -757,7 +742,7 @@ impl SolverAlgorithm for GreedySolver { problem: Problem, ) { let hint = FnvHashMap::default(); - let solution = problem.solve(hint, stop); + let solution = problem.naive_greedy_solver(hint, stop); if let Some((_, solution)) = solution { let solution = solution diff --git a/src/algorithms/mod.rs b/src/algorithms/mod.rs index b3fa609..407ff52 100644 --- a/src/algorithms/mod.rs +++ b/src/algorithms/mod.rs @@ -1,3 +1,5 @@ +//! This module provides you with a list of potential algorithms you may use to solve a reservation problem + use std::sync::mpsc::Receiver; use std::{ collections::HashMap, @@ -243,7 +245,7 @@ fn test_multisolver_algorithm_pool() { scenario_generation::generate_test_scenario_with_known_best, }; - use self::sat::SATSolver; + use self::sat::FixedTimeSATSolver; let (requests, resources) = //generate_sat_devil(5,3); generate_test_scenario_with_known_best(10, 10, 5); @@ -256,7 +258,7 @@ fn test_multisolver_algorithm_pool() { let problem = system.generate_literals_and_remap_requests(); let mut pool = AlgorithmPool::default(); - pool.add_algorithm(Arc::new(SATSolver)); + pool.add_algorithm(Arc::new(FixedTimeSATSolver)); pool.add_algorithm(Arc::new(GreedySolver)); let mtx = Arc::new(Mutex::new(AlgorithmState::NotFound)); pool.solve(problem, mtx); diff --git a/src/algorithms/sat.rs b/src/algorithms/sat.rs index c0b5777..1aaf63b 100644 --- a/src/algorithms/sat.rs +++ b/src/algorithms/sat.rs @@ -43,9 +43,12 @@ struct AssumptionList { assumptions: Vec>, } -pub struct SATSolver; -impl SolverAlgorithm for SATSolver { +/// This solver assumes that each alternative has a fixed starting time. However, it does take into account +/// the cost and can use an aribitrary cost function to solve. +pub struct FixedTimeSATSolver; + +impl SolverAlgorithm for FixedTimeSATSolver { fn iterative_solve( &self, result_channel: Sender, @@ -56,8 +59,8 @@ impl SolverAlgorithm for SATSolver { } } -impl SATSolver { - /// Set up the problem and solve it without any optimality check. +impl FixedTimeSATSolver { + /// Set up the problem and find a feasible solution, pub fn without_optimality_check(problem: Problem) { let conflicts = problem.get_banned_reservation_combinations(); let score_cache = problem.score_cache(); @@ -493,6 +496,6 @@ fn test_sat() { let timer = SystemTime::now(); let (sender, rx) = mpsc::channel(); let stop = Arc::new(AtomicBool::new(false)); - SATSolver::from_hill_climber_with_optimality_proof(soln.clone(), sender, stop); + FixedTimeSATSolver::from_hill_climber_with_optimality_proof(soln.clone(), sender, stop); let optimality_proof_dur = timer.elapsed(); } diff --git a/src/algorithms/sat_flexible_time_model.rs b/src/algorithms/sat_flexible_time_model.rs index 9f19a05..384ad42 100644 --- a/src/algorithms/sat_flexible_time_model.rs +++ b/src/algorithms/sat_flexible_time_model.rs @@ -103,7 +103,7 @@ fn shrink_reservation_request( } /// Solver for scenarios where there is a starting time range instead of a fixed starting time. -/// Note: The solvers in this class currently ignore thestarting time range. +/// Note: The solvers in this class currently ignore the cost of an alternative. /// You need to implement a clock source. The reason is that we needto have the current time as a starting point. pub struct SATFlexibleTimeModel { pub clock_source: CS, diff --git a/src/database/mod.rs b/src/database/mod.rs index 6aad475..af44371 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,3 +1,7 @@ +//! This module handles state management of a system that turns the algorithms into an online +//! reservation system. This part of the library is still unstable and undergoing frequent reworks. +//! Ultimately this will be the module exposed to end users. + use std::{collections::HashMap, default, fs::Metadata, hash::Hash, sync::Arc}; use chrono::{DateTime, Duration, Utc}; @@ -6,7 +10,7 @@ use serde_derive::{Deserialize, Serialize}; use crate::{ algorithms::{ greedy_solver::{ConflictTracker, GreedySolver, Problem}, - sat::SATSolver, + sat::FixedTimeSATSolver, sat_flexible_time_model::{Assignment as FlexibleAssignment, SATFlexibleTimeModel}, AlgorithmPool, AsyncExecutor, }, @@ -45,7 +49,7 @@ pub(crate) struct Snapshot { pub(crate) metadata: T, } -/// A reservation system that +/// This provides an abstract interface to the pub struct FixedTimeReservationSystem { resources: Vec, record: HashMap>, @@ -57,7 +61,7 @@ pub struct FixedTimeReservationSystem { impl FixedTimeReservationSystem { pub fn create_with_resources(resources: Vec) -> Self { let mut alg_pool = AlgorithmPool::::default(); - alg_pool.add_algorithm(Arc::new(SATSolver)); + alg_pool.add_algorithm(Arc::new(FixedTimeSATSolver)); alg_pool.add_algorithm(Arc::new(GreedySolver)); Self { diff --git a/src/lib.rs b/src/lib.rs index dfb1bc1..c339b24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,13 @@ +//! This is a library that provides a solver for constrained resource scheduling for multi-robot applications. More specifically, +//! we provide a very simple formulation for resource optimization and scheduling. A robot may request the use of a +//! resource like a charger for a fixed duration of time within a given time range. The system will then assign the robot +//! to said resource. +//! +//! At 10,000ft the library solves the following problem: +//! > Suppose you have n robots declaring that “I'd like to use one of (resource 1, resource 2, resource 3) for (d1, d2, d3) minutes starting at a certain time. Each alternative has some cost c(t).” +//! +//! To specify such a problem take a look at [ReservationRequestAlternative] which provides a wrapper around one such alternative. + #![feature(btree_cursors)] #![feature(hasher_prefixfree_extras)] #![feature(test)]