From 3bef331564078fa0ece1c850518d41efe2c22b18 Mon Sep 17 00:00:00 2001 From: Jacob Finkelman Date: Thu, 19 Dec 2024 03:50:05 -0500 Subject: [PATCH] when priorities are equal do breadth first search (#299) * when priorities are equal do breadth first search * Lints and docs --------- Co-authored-by: konstin --- src/internal/partial_solution.rs | 9 +++++++-- src/solver.rs | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/internal/partial_solution.rs b/src/internal/partial_solution.rs index 2d71e598..f1345634 100644 --- a/src/internal/partial_solution.rs +++ b/src/internal/partial_solution.rs @@ -3,6 +3,7 @@ //! A Memory acts like a structured partial solution //! where terms are regrouped by package in a [Map](crate::type_aliases::Map). +use std::cmp::Reverse; use std::fmt::{Debug, Display}; use std::hash::BuildHasherDefault; @@ -66,8 +67,12 @@ pub(crate) struct PartialSolution { /// The undecided packages order by their `Priority`. /// /// The max heap allows quickly `pop`ing the highest priority package. + /// + /// The `Reverse` is the discovery order of packages used as tiebreaker. Its order is that + /// of a breadth-first search. + #[allow(clippy::type_complexity)] prioritized_potential_packages: - PriorityQueue, DP::Priority, BuildHasherDefault>, + PriorityQueue, (DP::Priority, Reverse), BuildHasherDefault>, /// Whether we have never backtracked, to enable fast path optimizations. has_ever_backtracked: bool, } @@ -330,7 +335,7 @@ impl PartialSolution { .filter_map(|(&p, pa)| pa.assignments_intersection.potential_package_filter(p)) .for_each(|(p, r)| { let priority = prioritizer(p, r); - prioritized_potential_packages.push(p, priority); + prioritized_potential_packages.push(p, (priority, Reverse(p.into_raw() as u32))); }); self.prioritize_decision_level = self.package_assignments.len(); prioritized_potential_packages.pop().map(|(p, _)| p) diff --git a/src/solver.rs b/src/solver.rs index e6ba6249..7c4ed0f8 100644 --- a/src/solver.rs +++ b/src/solver.rs @@ -323,6 +323,11 @@ pub trait DependencyProvider { /// > since these packages will run out of versions to try more quickly. /// > But there's likely room for improvement in these heuristics. /// + /// The `package_conflicts_counts` argument provides access to some other heuristics that + /// are production users have found useful. Although the exact meaning/efficacy of those arguments may change. + /// + /// If two packages have the same priority, PubGrub will biased toward a breadth first search. + /// /// Note: the resolver may call this even when the range has not changed, /// if it is more efficient for the resolvers internal data structures. fn prioritize(