Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Dominance trait #20

Merged
merged 6 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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