Skip to content

Commit

Permalink
Merge pull request #23 from domain-independent-dp/hotfix-0.7.2
Browse files Browse the repository at this point in the history
Hotfix 0.7.2
  • Loading branch information
Kurorororo committed Mar 9, 2024
2 parents 1e37c9d + 4386481 commit 2ffd599
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 33 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions didp-yaml/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "didp-yaml"
version = "0.7.1"
version = "0.7.2"
edition = "2021"
rust-version = "1.65"
description = "YAML interface for Dynamic Programming Description Language (DyPDL) and DyPDL solvers."
Expand All @@ -12,8 +12,8 @@ repository = "https://github.com/domain-independent-dp/didp-rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dypdl = { path = "../dypdl", version = "0.7.1" }
dypdl-heuristic-search = { path = "../dypdl-heuristic-search", version = "0.7.1" }
dypdl = { path = "../dypdl", version = "0.7.2" }
dypdl-heuristic-search = { path = "../dypdl-heuristic-search", version = "0.7.2" }
rustc-hash = "1.1"
yaml-rust = "0.4"
linked-hash-map = "0.5"
Expand Down
2 changes: 1 addition & 1 deletion didp-yaml/docs/solver-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ config:
- default: `2023`
- `has_negative_cost`: whether the cost of a transition can be negative.
- default: `false`
- `use_cost_weight`: use weighted sampling biased by costs to select a start of a partial path. This is not activated when `has_negative_cost` is `true`.
- `use_cost_weight`: use weighted sampling biased by costs to select a start of a partial path.
- default: `false`
- `no_bandit`: do not use bandit-based sampling to select the depth of a partial path.
- default: `false`
Expand Down
6 changes: 3 additions & 3 deletions didppy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "didppy"
version = "0.7.1"
version = "0.7.2"
edition = "2021"
rust-version = "1.65"
description = "Python interface for Dynamic Programming Description Language (DyPDL) and DyPDL solvers."
Expand All @@ -15,8 +15,8 @@ name = "didppy"
crate-type = ["cdylib"]

[dependencies]
dypdl = { path = "../dypdl", version = "0.7.1" }
dypdl-heuristic-search = { path = "../dypdl-heuristic-search", version = "0.7.1" }
dypdl = { path = "../dypdl", version = "0.7.2" }
dypdl-heuristic-search = { path = "../dypdl-heuristic-search", version = "0.7.2" }
rustc-hash = "1.1"

[dependencies.pyo3]
Expand Down
2 changes: 2 additions & 0 deletions didppy/docs/papers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ DIDP Papers
* This paper introduces Large Neighborhood Beam Search (LNBS).
* Ryo Kuroiwa and J. Christopher Beck. `Parallel Beam Search Algorithms for Domain-Independent Dynamic Programming <https://tidel.mie.utoronto.ca/pubs/aaai24-parallel-camera-ready.pdf>`_. In Proceedings of the 38th Annual AAAI Conference on Artificial Intelligence (AAAI). 2024.
* This paper parallelizes :class:`~didppy.CABS`.
* Ryo Kuroiwa and J. Christopher Beck. `Domain-Independent Dynamic Programming <https://arxiv.org/pdf/2401.13883.pdf>`_. arXiv. 2024.
* This paper provides formal definitions of the modeling language and solvers for DIDP. It also introduces DIDP models for the orienteering problem with time windows and the multi-dimensional knapsack problem.

5 changes: 3 additions & 2 deletions didppy/docs/solver-selection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ However, these alternatives consume more memory than :class:`didppy.CABS`, so if
The experimental comparison of :class:`~didppy.CAASDy` and the anytime solvers is provided in :cite:t:`DIDPAnytime`.

If the time to prove optimality is not very important, and you want to find a good solution quickly, :class:`~didppy.LNBS` may be also useful.
It is slower than :class:`~didppy.CABS` to prove the optimality, but it tends to find a better solution quickly in routing and scheduling problems such as :ref:`TSPTW <tutorial:TSPTW>` and :ref:`talent scheduling <advanced-tutorials/forced-transitions:Talent Scheduling>`.
In contrast, :class:`~didppy.CABS` is better in :ref:`MOSP <advanced-tutorials/general-cost:MOSP>` for example.
It is slower than :class:`~didppy.CABS` to prove the optimality, but it tends to find a better solution quickly when the dual bound functions are not tight.
For example, :class:`~didppy.LNBS` is better than :class:`~didppy.CABS` with the DIDP models for :ref:`TSPTW <tutorial:TSPTW>` and :ref:`talent scheduling <advanced-tutorials/forced-transitions:Talent Scheduling>`.
In contrast, :class:`~didppy.CABS` is better with the DIDP model for :ref:`MOSP <advanced-tutorials/general-cost:MOSP>` for example.


Layer-by-Layer Search
Expand Down
3 changes: 1 addition & 2 deletions didppy/src/heuristic_search_solver/lnbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::sync::Arc;
/// This performs LNBS using the dual bound as the heuristic function.
/// LNBS is complete, i.e., eventually finds the optimal solution, but is designed to find a good solution rather than proving the optimality.
/// If you want to prove the optimality, :class:`didppy.CABS` or :class:`didppy.CAASDy` might be better.
/// LNBS typically performs well in routing and scheduling problems, where solution costs are diverse.
/// LNBS typically performs better when the dual bound functions are not tight.
///
/// To apply this solver, the cost must be computed in the form of :code:`x + state_cost`, :code:`x * state_cost`, :code:`didppy.max(x, state_cost)`,
/// or :code:`didppy.min(x, state_cost)` where, :code:`state_cost` is either of :meth:`IntExpr.state_cost()` and :meth:`FloatExpr.state_cost()`,
Expand Down Expand Up @@ -63,7 +63,6 @@ use std::sync::Arc;
/// Whether the cost of a transition can be negative.
/// use_cost_weight: bool, default: False
/// Use weighted sampling biased by costs to select a start of a partial path.
/// This is not activated when :code:`has_negative_cost` is :code:`True`.
/// no_bandit: bool, default: False
/// Do not use bandit-based sampling to select the depth of a partial path.
/// no_transition_mutex: bool, default: False
Expand Down
4 changes: 2 additions & 2 deletions dypdl-heuristic-search/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dypdl-heuristic-search"
version = "0.7.1"
version = "0.7.2"
edition = "2021"
rust-version = "1.65"
description = "Heuristic search solvers for Dynamic Programming Description Language (DyPDL)."
Expand All @@ -13,7 +13,7 @@ repository = "https://github.com/domain-independent-dp/didp-rs"

[dependencies]
ordered-float = "3.9"
dypdl = { path = "../dypdl", version = "0.7.1" }
dypdl = { path = "../dypdl", version = "0.7.2" }
rustc-hash = "1.1"
dashmap = "5.5"
rayon = "1.8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl TerminationDetector {

/// Notifies that a message has been received.
pub fn notify_received(&mut self, tstamp: usize) {
self.clock = max(tstamp, self.clock);
self.tmax = max(tstamp, self.tmax);
self.count -= 1;
}

Expand Down
75 changes: 61 additions & 14 deletions dypdl-heuristic-search/src/search_algorithm/lnbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ where
}
}

//// Search for the next solution, returning the solution using `TransitionWithId`.
/// Search for the next solution, returning the solution using `TransitionWithId`.
pub fn search_inner(&mut self) -> (Solution<T, TransitionWithId<V>>, bool) {
if self.input.solution.is_terminated() || self.input.solution.cost.is_none() {
return (self.input.solution.clone(), true);
Expand Down Expand Up @@ -443,7 +443,8 @@ where

let current_cost = self.input.solution.cost.unwrap();
let reward = (cost - current_cost).to_continuous().abs()
/ current_cost.to_continuous().abs();
/ cmp::max(cost.abs(), current_cost.abs()).to_continuous();
let reward = if reward > 1.0 { 1.0 } else { reward };
let time = (self.time_keeper.elapsed_time() - time_start) / self.time_limit;
self.update_bandit(arm, reward, time);

Expand Down Expand Up @@ -573,7 +574,7 @@ where
}

fn select_start(&mut self, costs: &[T], depth: usize) -> Option<(usize, usize)> {
let search_non_positive = self.has_negative_cost
let not_cost_algebraic_minimization = self.has_negative_cost
|| self.input.successor_generator.model.reduce_function == ReduceFunction::Max;

let (weights, starts): (Vec<_>, Vec<_>) = std::iter::once(T::zero())
Expand All @@ -586,9 +587,9 @@ where
.entry((start, depth))
.or_insert((self.initial_beam_size, false));

if entry.1 || (!search_non_positive && after <= before) {
if entry.1 || (!not_cost_algebraic_minimization && after <= before) {
None
} else if !search_non_positive && self.use_cost_weight {
} else if self.use_cost_weight {
Some((after - before, (start, entry.0)))
} else {
Some((T::one(), (start, entry.0)))
Expand All @@ -600,17 +601,63 @@ where
return None;
}

let mut weights = weights
.iter()
.map(|v| v.to_continuous())
.collect::<Vec<_>>();
let weights = if not_cost_algebraic_minimization && self.use_cost_weight {
if self.input.successor_generator.model.reduce_function == ReduceFunction::Max {
let max_weight = weights.iter().copied().max().unwrap();

if let Some(second_max) = weights.iter().copied().filter(|v| *v < max_weight).max()
{
weights
.into_iter()
.zip(starts.iter())
.map(|(v, (_, beam_size))| {
(max_weight - cmp::min(v, second_max)).to_continuous()
/ *beam_size as f64
})
.collect()
} else {
weights
.into_iter()
.zip(starts.iter())
.map(|(_, (_, beam_size))| 1.0 / *beam_size as f64)
.collect()
}
} else {
let min_weight = weights.iter().copied().min().unwrap();

if let Some(second_min) = weights.iter().copied().filter(|v| *v > min_weight).min()
{
weights
.into_iter()
.zip(starts.iter())
.map(|(v, (_, beam_size))| {
(cmp::max(v, second_min) - min_weight).to_continuous()
/ *beam_size as f64
})
.collect()
} else {
weights
.into_iter()
.zip(starts.iter())
.map(|(_, (_, beam_size))| 1.0 / *beam_size as f64)
.collect()
}
}
} else {
let mut weights = weights
.iter()
.map(|v| v.to_continuous())
.collect::<Vec<_>>();

if self.use_cost_weight {
weights
.iter_mut()
.zip(starts.iter())
.for_each(|(v, (_, beam_size))| *v /= *beam_size as f64);
}

if !search_non_positive && self.use_cost_weight {
weights
.iter_mut()
.zip(starts.iter())
.for_each(|(v, (_, beam_size))| *v /= *beam_size as f64);
}
};

let dist = WeightedIndex::new(weights).unwrap();

Expand Down
2 changes: 1 addition & 1 deletion dypdl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dypdl"
version = "0.7.1"
version = "0.7.2"
edition = "2021"
rust-version = "1.65"
description = "Libarary for Dynamic Programming Description Language (DyPDL)."
Expand Down

0 comments on commit 2ffd599

Please sign in to comment.