Skip to content

Commit

Permalink
Merge pull request #20 from vcoppe/dominance
Browse files Browse the repository at this point in the history
Update Dominance trait
  • Loading branch information
xgillard committed Jun 7, 2023
2 parents 2ec2e41 + d6063ba commit a37a722
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 81 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,15 @@ impl Dominance for KPDominance {
type State = KnapsackState;
type Key = usize;

fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
Some(state.depth)
}

fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
fn nb_dimensions(&self, _state: &Self::State) -> usize {
1
}

fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
state.capacity as isize
}

Expand Down
2 changes: 2 additions & 0 deletions ddo/examples/golomb/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ fn main() {
let relaxation = GolombRelax{pb: &problem};
let heuristic = Golombranking;
let width = max_width(problem.nb_variables(), args.width);
let dominance = EmptyDominanceChecker::default();
let cutoff = TimeBudget::new(Duration::from_secs(args.timeout));//NoCutoff;
let mut fringe = SimpleFringe::new(MaxUB::new(&heuristic));

Expand All @@ -239,6 +240,7 @@ fn main() {
&relaxation,
&heuristic,
width.as_ref(),
&dominance,
&cutoff,
&mut fringe,
);
Expand Down
2 changes: 2 additions & 0 deletions ddo/examples/golomb/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub fn solve_golomb(n: usize) -> isize {
let relaxation = GolombRelax{pb: &problem};
let heuristic = Golombranking;
let width = NbUnassignedWitdh(problem.nb_variables());
let dominance = EmptyDominanceChecker::default();
let cutoff = NoCutoff;
let mut fringe = SimpleFringe::new(MaxUB::new(&heuristic));

Expand All @@ -36,6 +37,7 @@ pub fn solve_golomb(n: usize) -> isize {
&relaxation,
&heuristic,
&width,
&dominance,
&cutoff,
&mut fringe,
);
Expand Down
8 changes: 4 additions & 4 deletions ddo/examples/knapsack/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! This example show how to implement a solver for the knapsack problem using ddo.
//! It is a fairly simple example but features most of the aspects you will want to
//! copy when implementing your own solver.
use std::{path::Path, fs::File, io::{BufReader, BufRead}, time::{Duration, Instant}, num::ParseIntError};
use std::{path::Path, fs::File, io::{BufReader, BufRead}, time::{Duration, Instant}, num::ParseIntError, sync::Arc};

use clap::Parser;
use ddo::*;
Expand Down Expand Up @@ -176,15 +176,15 @@ impl Dominance for KPDominance {
type State = KnapsackState;
type Key = usize;

fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
Some(state.depth)
}

fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
fn nb_dimensions(&self, _state: &Self::State) -> usize {
1
}

fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
state.capacity as isize
}

Expand Down
73 changes: 32 additions & 41 deletions ddo/src/abstraction/dominance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,69 +22,60 @@ use std::{cmp::Ordering, sync::Arc};
/// This trait abstracts gives the possibility to model dominance relations
/// between the states of a specific problem. The dominance relation is evaluated
/// only for pairs of states that are mapped to the same key. A dominance relation
/// exists if the values of a state are greater or equal than those of another state
/// exists if the coordinates of a state are greater or equal than those of another state
/// for all given dimensions. The value obtained by the solver for each state can
/// optionally be included in the comparison.
/// optionally be used as a coordinate in the comparison.
pub trait Dominance {
type State;
type Key;

/// Takes a state and returns a key that maps it to comparable states
fn get_key(&self, state: &Self::State) -> Option<Self::Key>;
fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key>;

/// Returns the number of dimensions that capture the value of a state
fn nb_value_dimensions(&self, state: &Self::State) -> usize;
/// Returns the number of dimensions to include in the comparison
fn nb_dimensions(&self, state: &Self::State) -> usize;

/// Returns the i-th component of the value associated with the given state
/// Returns the i-th coordinate associated with the given state
/// Greater is better for the dominance check
fn get_value_at(&self, state: &Self::State, i: usize) -> isize;
fn get_coordinate(&self, state: &Self::State, i: usize) -> isize;

/// Whether to include the value in the dominance check
/// Whether to include the value as a coordinate in the dominance check
fn use_value(&self) -> bool { false }

/// Checks whether there is a dominance relation between the two states, given the values
/// provided by the function get_value_at evaluated for all i in 0..self.nb_value_dimensions()
/// Checks whether there is a dominance relation between the two states, given the coordinates
/// provided by the function get_coordinate evaluated for all i in 0..self.nb_dimensions()
/// Note: the states are assumed to have the same key, otherwise they are not comparable for dominance
fn partial_cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Option<Ordering> {
let mut ordering = Ordering::Equal;
if self.use_value() {
if val_a < val_b {
ordering = Ordering::Less;
} else if val_a > val_b {
ordering = Ordering::Greater;
}
ordering = val_a.cmp(&val_b);
}
for i in 0..self.nb_value_dimensions(a) {
let val_a = self.get_value_at(a, i);
let val_b = self.get_value_at(b, i);

if val_a < val_b {
if ordering == Ordering::Greater {
return None;
} else if ordering == Ordering::Equal {
ordering = Ordering::Less;
}
} else if val_a > val_b {
if ordering == Ordering::Less {
return None;
} else if ordering == Ordering::Equal {
ordering = Ordering::Greater;
}
for i in 0..self.nb_dimensions(a) {
match (ordering, self.get_coordinate(a, i).cmp(&self.get_coordinate(b, i))) {
(Ordering::Less, Ordering::Greater) => return None,
(Ordering::Greater, Ordering::Less) => return None,
(Ordering::Equal, Ordering::Greater) => ordering = Ordering::Greater,
(Ordering::Equal, Ordering::Less) => ordering = Ordering::Less,
(_, _) => (),
}
}
Some(ordering)
}

/// Comparator to order states by increasing value, regardless of their key
fn cmp(&self, a: &Self::State, b: &Self::State) -> Ordering {
for i in 0..self.nb_value_dimensions(a) {
let val_a = self.get_value_at(a, i);
let val_b = self.get_value_at(b, i);

if val_a < val_b {
return Ordering::Less;
} else if val_a > val_b {
return Ordering::Greater;
fn cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Ordering {
if self.use_value() {
match val_a.cmp(&val_b) {
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
Ordering::Equal => (),
}
}
for i in 0..self.nb_dimensions(a) {
match self.get_coordinate(a, i).cmp(&self.get_coordinate(b, i)) {
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
Ordering::Equal => (),
}
}
Ordering::Equal
Expand All @@ -100,6 +91,6 @@ pub trait DominanceChecker {
fn is_dominated_or_insert(&self, state: Arc<Self::State>, value: isize) -> bool;

/// Comparator to order states by increasing value, regardless of their key
fn cmp(&self, a: &Self::State, b: &Self::State) -> Ordering;
fn cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Ordering;

}
2 changes: 1 addition & 1 deletion ddo/src/implementation/dominance/empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl<T> DominanceChecker for EmptyDominanceChecker<T> {
false
}

fn cmp(&self, _: &Self::State, _: &Self::State) -> Ordering {
fn cmp(&self, _: &Self::State, _: isize, _: &Self::State, _: isize) -> Ordering {
Ordering::Equal
}
}
6 changes: 3 additions & 3 deletions ddo/src/implementation/dominance/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ where
type State = D::State;

fn is_dominated_or_insert(&self, state: Arc<Self::State>, value: isize) -> bool {
if let Some(key) = self.dominance.get_key(state.as_ref()) {
if let Some(key) = self.dominance.get_key(state.clone()) {
match self.data.entry(key) {
Entry::Occupied(mut e) => {
let mut dominated = false;
Expand Down Expand Up @@ -94,7 +94,7 @@ where
}
}

fn cmp(&self, a: &Self::State, b: &Self::State) -> Ordering {
self.dominance.cmp(a, b)
fn cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Ordering {
self.dominance.cmp(a, val_a, b, val_b)
}
}
14 changes: 8 additions & 6 deletions ddo/src/implementation/heuristics/cutoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::Cutoff;
///
/// ```
/// # use ddo::*;
/// # use std::sync::Arc;
/// #
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// pub struct KnapsackState {
Expand Down Expand Up @@ -118,13 +119,13 @@ use crate::Cutoff;
/// // details omitted in this example
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down Expand Up @@ -172,6 +173,7 @@ impl Cutoff for NoCutoff {
/// ```
/// # use std::time::Duration;
/// # use ddo::*;
/// # use std::sync::Arc;
/// #
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// pub struct KnapsackState {
Expand Down Expand Up @@ -257,13 +259,13 @@ impl Cutoff for NoCutoff {
/// // details omitted in this example
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down
25 changes: 13 additions & 12 deletions ddo/src/implementation/heuristics/width.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,13 @@ use crate::{WidthHeuristic, SubProblem};
/// # impl Dominance for KPDominance {
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down Expand Up @@ -358,13 +358,13 @@ impl <X> WidthHeuristic<X> for FixedWidth {
/// // details omitted in this example
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down Expand Up @@ -597,13 +597,13 @@ impl <X> WidthHeuristic<X> for NbUnassignedWitdh {
/// // details omitted in this example
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down Expand Up @@ -752,6 +752,7 @@ impl <S, X: WidthHeuristic<S>> WidthHeuristic<S> for Times<X> {
///
/// ```
/// # use ddo::*;
/// # use std::sync::Arc;
/// #
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// pub struct KnapsackState {
Expand Down Expand Up @@ -836,13 +837,13 @@ impl <S, X: WidthHeuristic<S>> WidthHeuristic<S> for Times<X> {
/// // details omitted in this example
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion ddo/src/implementation/mdd/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ where
}

fn _filter_with_dominance(&mut self, input: &CompilationInput<T>, curr_l: &mut Vec<NodeId>) {
curr_l.sort_unstable_by(|a,b| input.dominance.cmp(get!(node a, self).state.as_ref(), get!(node b, self).state.as_ref()).reverse());
curr_l.sort_unstable_by(|a,b| input.dominance.cmp(get!(node a, self).state.as_ref(), get!(node a, self).value_top, get!(node b, self).state.as_ref(), get!(node b, self).value_top).reverse());
curr_l.retain(|id| {
let node = get!(mut node id, self);
if node.flags.is_exact() {
Expand Down
2 changes: 1 addition & 1 deletion ddo/src/implementation/mdd/pooled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ where
}

fn _filter_with_dominance(&mut self, input: &CompilationInput<T>, curr_l: &mut Vec<NodeId>) {
curr_l.sort_unstable_by(|a,b| input.dominance.cmp(get!(node a, self).state.as_ref(), get!(node b, self).state.as_ref()).reverse());
curr_l.sort_unstable_by(|a,b| input.dominance.cmp(get!(node a, self).state.as_ref(), get!(node a, self).value_top, get!(node b, self).state.as_ref(), get!(node b, self).value_top).reverse());
curr_l.retain(|id| {
let node = get!(mut node id, self);
if node.flags.is_exact() {
Expand Down
7 changes: 4 additions & 3 deletions ddo/src/implementation/solver/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ enum WorkLoad<T> {
/// # Example Usage
/// ```
/// # use ddo::*;
/// # use std::sync::Arc;
/// #
/// # #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// # pub struct KnapsackState {
Expand Down Expand Up @@ -210,13 +211,13 @@ enum WorkLoad<T> {
/// # impl Dominance for KPDominance {
/// # type State = KnapsackState;
/// # type Key = usize;
/// # fn get_key(&self, state: &Self::State) -> Option<Self::Key> {
/// # fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
/// # Some(state.depth)
/// # }
/// # fn nb_value_dimensions(&self, _state: &Self::State) -> usize {
/// # fn nb_dimensions(&self, _state: &Self::State) -> usize {
/// # 1
/// # }
/// # fn get_value_at(&self, state: &Self::State, _: usize) -> isize {
/// # fn get_coordinate(&self, state: &Self::State, _: usize) -> isize {
/// # state.capacity as isize
/// # }
/// # fn use_value(&self) -> bool {
Expand Down
Loading

0 comments on commit a37a722

Please sign in to comment.