Skip to content

Commit

Permalink
less O(n^2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eh2406 committed Oct 22, 2022
1 parent 78562c5 commit dff95d0
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 30 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ include = ["Cargo.toml", "LICENSE", "README.md", "src/**", "tests/**", "examples
[dependencies]
thiserror = "1.0"
rustc-hash = "1.1.0"
indexmap = "1.6.2"
serde = { version = "1.0", features = ["derive"], optional = true }
log = "0.4.14" # for debug logs in tests

Expand Down
53 changes: 28 additions & 25 deletions src/internal/partial_solution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ use crate::internal::incompatibility::{IncompId, Incompatibility, Relation};
use crate::internal::small_map::SmallMap;
use crate::package::Package;
use crate::term::Term;
use crate::type_aliases::{Map, SelectedDependencies};
use crate::type_aliases::SelectedDependencies;
use crate::version_set::VersionSet;

use super::small_vec::SmallVec;

use std::hash::BuildHasherDefault;

type FnvIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;

#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct DecisionLevel(pub u32);

Expand All @@ -30,7 +34,7 @@ impl DecisionLevel {
pub struct PartialSolution<P: Package, VS: VersionSet> {
next_global_index: u32,
current_decision_level: DecisionLevel,
package_assignments: Map<P, PackageAssignments<P, VS>>,
package_assignments: FnvIndexMap<P, PackageAssignments<P, VS>>,
}

impl<P: Package, VS: VersionSet> Display for PartialSolution<P, VS> {
Expand Down Expand Up @@ -126,7 +130,7 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
Self {
next_global_index: 0,
current_decision_level: DecisionLevel(0),
package_assignments: Map::default(),
package_assignments: FnvIndexMap::default(),
}
}

Expand All @@ -146,17 +150,21 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
},
}
}
let new_idx = self.current_decision_level.0 as usize;
self.current_decision_level = self.current_decision_level.increment();
let mut pa = self
let (old_idx, _, mut pa) = self
.package_assignments
.get_mut(&package)
.get_full_mut(&package)
.expect("Derivations must already exist");
pa.highest_decision_level = self.current_decision_level;
pa.assignments_intersection = AssignmentsIntersection::Decision((
self.next_global_index,
version.clone(),
Term::exact(version),
));
if new_idx != old_idx {
self.package_assignments.swap_indices(new_idx, old_idx);
}
self.next_global_index += 1;
}

Expand All @@ -167,7 +175,7 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
cause: IncompId<P, VS>,
store: &Arena<Incompatibility<P, VS>>,
) {
use std::collections::hash_map::Entry;
use indexmap::map::Entry;
let term = store[cause].get(&package).unwrap().negate();
let dated_derivation = DatedDerivation {
global_index: self.next_global_index,
Expand Down Expand Up @@ -208,9 +216,8 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
/// and if it contains at least one positive derivation term
/// in the partial solution.
pub fn potential_packages(&self) -> Option<impl Iterator<Item = (&P, &VS)>> {
let mut iter = self
.package_assignments
.iter()
let mut iter = (self.current_decision_level.0 as usize..self.package_assignments.len())
.map(move |i| self.package_assignments.get_index(i).unwrap())
.filter_map(|(p, pa)| pa.assignments_intersection.potential_package_filter(p))
.peekable();
if iter.peek().is_some() {
Expand All @@ -223,21 +230,17 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
/// If a partial solution has, for every positive derivation,
/// a corresponding decision that satisfies that assignment,
/// it's a total solution and version solving has succeeded.
pub fn extract_solution(&self) -> Option<SelectedDependencies<P, VS::V>> {
let mut solution = Map::default();
for (p, pa) in &self.package_assignments {
match &pa.assignments_intersection {
AssignmentsIntersection::Decision((_, v, _)) => {
solution.insert(p.clone(), v.clone());
}
AssignmentsIntersection::Derivations(term) => {
if term.is_positive() {
return None;
}
pub fn extract_solution(&self) -> SelectedDependencies<P, VS::V> {
self.package_assignments
.iter()
.take(self.current_decision_level.0 as usize)
.map(|(p, pa)| match &pa.assignments_intersection {
AssignmentsIntersection::Decision((_, v, _)) => (p.clone(), v.clone()),
AssignmentsIntersection::Derivations(_) => {
panic!("Derivations in the Decision part")
}
}
}
Some(solution)
})
.collect()
}

/// Backtrack the partial solution to a given decision level.
Expand Down Expand Up @@ -380,7 +383,7 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
/// to return a coherent previous_satisfier_level.
fn find_satisfier(
incompat: &Incompatibility<P, VS>,
package_assignments: &Map<P, PackageAssignments<P, VS>>,
package_assignments: &FnvIndexMap<P, PackageAssignments<P, VS>>,
store: &Arena<Incompatibility<P, VS>>,
) -> SmallMap<P, (usize, u32, DecisionLevel)> {
let mut satisfied = SmallMap::Empty;
Expand All @@ -401,7 +404,7 @@ impl<P: Package, VS: VersionSet> PartialSolution<P, VS> {
incompat: &Incompatibility<P, VS>,
satisfier_package: &P,
mut satisfied_map: SmallMap<P, (usize, u32, DecisionLevel)>,
package_assignments: &Map<P, PackageAssignments<P, VS>>,
package_assignments: &FnvIndexMap<P, PackageAssignments<P, VS>>,
store: &Arena<Incompatibility<P, VS>>,
) -> DecisionLevel {
// First, let's retrieve the previous derivations and the initial accum_term.
Expand Down
6 changes: 1 addition & 5 deletions src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,7 @@ pub fn resolve<P: Package, VS: VersionSet>(
// The borrow checker did not like using a match on potential_packages.
// This `if ... is_none ... drop` is a workaround.
// I believe this is a case where Polonius could help, when and if it lands in rustc.
return state.partial_solution.extract_solution().ok_or_else(|| {
PubGrubError::Failure(
"How did we end up with no package to choose but no solution?".into(),
)
});
return Ok(state.partial_solution.extract_solution());
}
let decision = dependency_provider
.choose_package_version(potential_packages.unwrap())
Expand Down

0 comments on commit dff95d0

Please sign in to comment.