use seq::*;
pub mod seq;
pub trait BranchingOperator: Sized {
fn branch(&self) -> Vec<Self>;
}
pub trait BoundingOperator<V>
where
V: PartialOrd,
{
fn bound(&self) -> V;
fn solution(&self) -> Option<V>;
}
pub struct BBMin();
pub struct BBMax();
pub trait MinOrMax {
fn is_maximize(&self) -> bool;
}
impl MinOrMax for BBMin {
fn is_maximize(&self) -> bool {
false
}
}
impl MinOrMax for BBMax {
fn is_maximize(&self) -> bool {
true
}
}
pub struct BranchAndBound<V, B, S, M>
where
V: PartialOrd + Clone,
B: BranchingOperator + BoundingOperator<V>,
S: NodeSequencer<BoundedSolution<V, B>>,
M: MinOrMax,
{
start_node: B,
current_best_bound: Option<(V, B)>,
node_sequencer: S,
goal_type: M,
iterations: usize,
}
impl<V, B> BranchAndBound<V, B, Stack<BoundedSolution<V, B>>, BBMin>
where
V: PartialOrd + Clone,
B: BranchingOperator + BoundingOperator<V> + Clone,
{
pub fn new(start_node: B) -> Self {
Self {
start_node: start_node.clone(),
current_best_bound: None,
node_sequencer: Stack::init(BoundedSolution::init(start_node)),
goal_type: BBMin(),
iterations: 0,
}
}
}
impl<V, B, S, M> BranchAndBound<V, B, S, M>
where
V: PartialOrd + Clone,
B: BranchingOperator + BoundingOperator<V>,
S: NodeSequencer<BoundedSolution<V, B>>,
M: MinOrMax,
{
pub fn minimize(self) -> BranchAndBound<V, B, S, BBMin> {
assert!(!self.node_sequencer.is_ordered());
BranchAndBound {
start_node: self.start_node,
current_best_bound: self.current_best_bound,
node_sequencer: self.node_sequencer,
goal_type: BBMin(),
iterations: self.iterations,
}
}
pub fn maximize(self) -> BranchAndBound<V, B, S, BBMax> {
assert!(!self.node_sequencer.is_ordered());
BranchAndBound {
start_node: self.start_node,
current_best_bound: self.current_best_bound,
node_sequencer: self.node_sequencer,
goal_type: BBMax(),
iterations: self.iterations,
}
}
pub fn use_dfs(self) -> BranchAndBound<V, B, Stack<BoundedSolution<V, B>>, M> {
BranchAndBound {
start_node: self.start_node,
current_best_bound: self.current_best_bound,
node_sequencer: Stack::convert_from(self.node_sequencer),
goal_type: self.goal_type,
iterations: self.iterations,
}
}
pub fn use_bfs(self) -> BranchAndBound<V, B, Queue<BoundedSolution<V, B>>, M> {
BranchAndBound {
start_node: self.start_node,
current_best_bound: self.current_best_bound,
node_sequencer: Queue::convert_from(self.node_sequencer),
goal_type: self.goal_type,
iterations: self.iterations,
}
}
pub fn with_start_solution(self, solution: B, value: V) -> Self {
Self {
start_node: self.start_node,
current_best_bound: Some((value, solution)),
node_sequencer: self.node_sequencer,
goal_type: self.goal_type,
iterations: self.iterations,
}
}
}
impl<V, B, S> BranchAndBound<V, B, S, BBMin>
where
V: PartialOrd + Clone,
B: BranchingOperator + BoundingOperator<V>,
S: NodeSequencer<BoundedSolution<V, B>>,
{
pub fn use_best_first_search(
self,
) -> BranchAndBound<V, B, PrioQueue<BoundedSolution<V, B>>, BBMin> {
BranchAndBound {
start_node: self.start_node,
current_best_bound: self.current_best_bound,
node_sequencer: PrioQueue::convert_from(self.node_sequencer),
goal_type: self.goal_type,
iterations: self.iterations,
}
}
}
impl<V, B, S> BranchAndBound<V, B, S, BBMax>
where
V: PartialOrd + Clone,
B: BranchingOperator + BoundingOperator<V>,
S: NodeSequencer<BoundedSolution<V, B>>,
{
pub fn use_best_first_search(
self,
) -> BranchAndBound<V, B, RevPrioQueue<BoundedSolution<V, B>>, BBMax> {
BranchAndBound {
start_node: self.start_node,
current_best_bound: self.current_best_bound,
node_sequencer: RevPrioQueue::convert_from(self.node_sequencer),
goal_type: self.goal_type,
iterations: self.iterations,
}
}
}
impl<V, B, S, M> BranchAndBound<V, B, S, M>
where
V: PartialOrd + Clone,
B: BranchingOperator + BoundingOperator<V>,
S: NodeSequencer<BoundedSolution<V, B>>,
M: MinOrMax,
{
pub fn execute_step(&mut self) {
self.iterations += 1;
if let Some(node) = self.node_sequencer.pop_until_satisfied(|node| {
if let Some((val, _)) = self.current_best_bound.as_ref() {
if (self.goal_type.is_maximize() && node.value() <= *val)
|| (!self.goal_type.is_maximize() && node.value() >= *val)
{
return false;
}
}
true
}) {
let (_, node) = node.split();
for branch_node in node.branch() {
if let Some(sol) = branch_node.solution() {
if let Some((val, _)) = self.current_best_bound.as_ref() {
if (self.goal_type.is_maximize() && sol > *val)
|| (!self.goal_type.is_maximize() && sol < *val)
{
self.current_best_bound = Some((sol, branch_node));
}
} else {
self.current_best_bound = Some((sol, branch_node));
}
continue;
}
let bound = branch_node.bound();
if let Some((val, _)) = self.current_best_bound.as_ref() {
if (self.goal_type.is_maximize() && bound <= *val)
|| (!self.goal_type.is_maximize() && bound >= *val)
{
continue;
}
}
self.node_sequencer
.push(BoundedSolution::new(bound, branch_node));
}
}
}
pub fn is_completed(&self) -> bool {
self.node_sequencer.len() == 0
}
pub fn run_to_completion(&mut self) {
while !self.is_completed() {
self.execute_step();
}
}
pub fn best_known_solution(&self) -> Option<&(V, B)> {
if let Some(sol) = self.current_best_bound.as_ref() {
return Some(sol);
}
None
}
pub fn num_iterations(&self) -> usize {
self.iterations
}
}