Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Oct 16, 2022
1 parent 78562c5 commit 46def28
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 46 deletions.
6 changes: 4 additions & 2 deletions examples/caching_dependency_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::error::Error;

use pubgrub::package::Package;
use pubgrub::range::Range;
use pubgrub::solver::{resolve, Dependencies, DependencyProvider, OfflineDependencyProvider};
use pubgrub::solver::{
resolve, Dependencies, DependencyProvider, OfflineDependencyProvider, Requirement,
};
use pubgrub::version::NumberVersion;
use pubgrub::version_set::VersionSet;

Expand Down Expand Up @@ -51,7 +53,7 @@ impl<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>> DependencyProvid
let dependencies = self.remote_dependencies.get_dependencies(package, version);
match dependencies {
Ok(Dependencies::Known(dependencies)) => {
cache.add_dependencies(
cache.add_requirements(
package.clone(),
version.clone(),
dependencies.clone(),
Expand Down
25 changes: 19 additions & 6 deletions src/internal/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::internal::partial_solution::{DecisionLevel, PartialSolution};
use crate::internal::small_vec::SmallVec;
use crate::package::Package;
use crate::report::DerivationTree;
use crate::solver::{Requirement, RequirementKind};
use crate::type_aliases::{DependencyConstraints, Map};
use crate::version_set::VersionSet;

Expand Down Expand Up @@ -75,14 +76,26 @@ impl<P: Package, VS: VersionSet> State<P, VS> {
&mut self,
package: P,
version: VS::V,
deps: &DependencyConstraints<P, VS>,
deps: &DependencyConstraints<P, Requirement<VS>>,
) -> std::ops::Range<IncompId<P, VS>> {
// Create incompatibilities and allocate them in the store.
let new_incompats_id_range = self
.incompatibility_store
.alloc_iter(deps.iter().map(|dep| {
Incompatibility::from_dependency(package.clone(), version.clone(), dep)
}));
let new_incompats_id_range =
self.incompatibility_store
.alloc_iter(
deps.iter()
.map(|(dep, requirement)| match requirement.kind {
RequirementKind::Required => Incompatibility::from_dependency(
package.clone(),
version.clone(),
(dep, &requirement.range),
),
RequirementKind::Constrained => Incompatibility::from_constraint(
package.clone(),
version.clone(),
(dep, &requirement.range),
),
}),
);
// Merge the newly created incompatibilities with the older ones.
for id in IncompId::range_to_iter(new_incompats_id_range.clone()) {
self.merge_incompatibility(id);
Expand Down
13 changes: 13 additions & 0 deletions src/internal/incompatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
}
}

/// Build an incompatibility from a given constraint.
pub fn from_constraint(package: P, version: VS::V, dep: (&P, &VS)) -> Self {
let set1 = VS::singleton(version);
let (p2, set2) = dep;
Self {
package_terms: SmallMap::Two([
(package.clone(), Term::Positive(set1.clone())),
(p2.clone(), Term::Positive(set2.complement())),
]),
kind: Kind::FromDependencyOf(package, set1, p2.clone(), set2.clone()),
}
}

/// Prior cause of two incompatibilities using the rule of resolution.
pub fn prior_cause(
incompat: Id<Self>,
Expand Down
88 changes: 81 additions & 7 deletions src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ pub fn resolve<P: Package, VS: VersionSet>(
version: v.clone(),
});
}
if let Some((dependent, _)) = x.iter().find(|(_, r)| r == &&VS::empty()) {
if let Some((dependent, _)) = x.iter().find(|(_, r)| {
r.kind == RequirementKind::Required && &r.range == &VS::empty()
}) {
return Err(PubGrubError::DependencyOnTheEmptySet {
package: p.clone(),
version: v.clone(),
Expand Down Expand Up @@ -215,7 +217,37 @@ pub enum Dependencies<P: Package, VS: VersionSet> {
/// Package dependencies are unavailable.
Unknown,
/// Container for all available package versions.
Known(DependencyConstraints<P, VS>),
Known(DependencyConstraints<P, Requirement<VS>>),
}

#[derive(Clone, Debug)]
pub struct Requirement<VS: VersionSet> {
pub range: VS,
pub kind: RequirementKind,
}

impl<VS: VersionSet> Requirement<VS> {
pub fn from_dependency(vs: VS) -> Self {
Self {
range: vs,
kind: RequirementKind::Required,
}
}
pub fn from_constraint(vs: VS) -> Self {
Self {
range: vs,
kind: RequirementKind::Constrained,
}
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RequirementKind {
/// A dependency that is resolved as part of the solution.
Required,

/// Constrains the version of package but does not require inclusion of the package.
Constrained,
}

/// Trait that allows the algorithm to retrieve available packages and their dependencies.
Expand Down Expand Up @@ -311,7 +343,7 @@ where
)]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct OfflineDependencyProvider<P: Package, VS: VersionSet> {
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, VS>>>,
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, Requirement<VS>>>>,
}

impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {
Expand All @@ -338,14 +370,52 @@ impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {
version: impl Into<VS::V>,
dependencies: I,
) {
let package_deps = dependencies.into_iter().collect();
let v = version.into();
*self
let entries = self
.dependencies
.entry(package)
.or_default()
.entry(v)
.or_default() = package_deps;
.or_default();
for (dep, range) in dependencies.into_iter() {
entries.insert(dep, Requirement::from_dependency(range));
}
}

pub fn add_constrains<I: IntoIterator<Item = (P, VS)>>(
&mut self,
package: P,
version: impl Into<VS::V>,
dependencies: I,
) {
let v = version.into();
let entries = self
.dependencies
.entry(package)
.or_default()
.entry(v)
.or_default();
for (package, constraint) in dependencies.into_iter() {
entries.insert(package, Requirement::from_constraint(constraint));
}
}

pub fn add_requirements<I: IntoIterator<Item = (P, Requirement<VS>)>>(
&mut self,
package: P,
version: impl Into<VS::V>,
dependencies: I,
) {
let v = version.into();
let entries = self
.dependencies
.entry(package)
.or_default()
.entry(v)
.or_default();
for (package, req) in dependencies.into_iter() {
entries.insert(package, req);
}
}

/// Lists packages that have been saved.
Expand All @@ -361,7 +431,11 @@ impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> {

/// Lists dependencies of a given package and version.
/// Returns [None] if no information is available regarding that package and version pair.
fn dependencies(&self, package: &P, version: &VS::V) -> Option<DependencyConstraints<P, VS>> {
fn dependencies(
&self,
package: &P,
version: &VS::V,
) -> Option<DependencyConstraints<P, Requirement<VS>>> {
self.dependencies.get(package)?.get(version).cloned()
}
}
Expand Down
76 changes: 47 additions & 29 deletions tests/proptest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use pubgrub::range::Range;
use pubgrub::report::{DefaultStringReporter, Reporter};
use pubgrub::solver::{
choose_package_with_fewest_versions, resolve, Dependencies, DependencyProvider,
OfflineDependencyProvider,
OfflineDependencyProvider, Requirement,
};
use pubgrub::version::{NumberVersion, SemanticVersion};
use pubgrub::version_set::VersionSet;
Expand All @@ -17,6 +17,7 @@ use proptest::collection::{btree_map, vec};
use proptest::prelude::*;
use proptest::sample::Index;
use proptest::string::string_regex;
use pubgrub::solver::RequirementKind::Required;

use crate::sat_dependency_provider::SatResolve;

Expand Down Expand Up @@ -146,7 +147,12 @@ pub fn registry_strategy<N: Package + Ord>(
let max_deps = max_versions * (max_crates * (max_crates - 1)) / shrinkage;

let raw_version_range = (any::<Index>(), any::<Index>());
let raw_dependency = (any::<Index>(), any::<Index>(), raw_version_range);
let raw_dependency = (
any::<Index>(),
any::<Index>(),
any::<bool>(),
raw_version_range,
);

fn order_index(a: Index, b: Index, size: usize) -> (usize, usize) {
use std::cmp::{max, min};
Expand All @@ -169,20 +175,22 @@ pub fn registry_strategy<N: Package + Ord>(
)
.prop_map(
move |(crate_vers_by_name, raw_dependencies, reverse_alphabetical, complicated_len)| {
let mut list_of_pkgid: Vec<((N, NumberVersion), Option<Vec<(N, NumVS)>>)> =
crate_vers_by_name
.iter()
.flat_map(|(name, vers)| {
vers.iter().map(move |x| {
(
(name.clone(), NumberVersion::from(x.0)),
if x.1 { Some(vec![]) } else { None },
)
})
let mut list_of_pkgid: Vec<(
(N, NumberVersion),
Option<Vec<(N, Requirement<NumVS>)>>,
)> = crate_vers_by_name
.iter()
.flat_map(|(name, vers)| {
vers.iter().map(move |x| {
(
(name.clone(), NumberVersion::from(x.0)),
if x.1 { Some(vec![]) } else { None },
)
})
.collect();
})
.collect();
let len_all_pkgid = list_of_pkgid.len();
for (a, b, (c, d)) in raw_dependencies {
for (a, b, required, (c, d)) in raw_dependencies {
let (a, b) = order_index(a, b, len_all_pkgid);
let (a, b) = if reverse_alphabetical { (b, a) } else { (a, b) };
let ((dep_name, _), _) = list_of_pkgid[a].to_owned();
Expand All @@ -194,18 +202,23 @@ pub fn registry_strategy<N: Package + Ord>(
let (c, d) = order_index(c, d, s.len());

if let (_, Some(deps)) = &mut list_of_pkgid[b] {
let range = if c == 0 && d == s_last_index {
Range::full()
} else if c == 0 {
Range::strictly_lower_than(s[d].0 + 1)
} else if d == s_last_index {
Range::higher_than(s[c].0)
} else if c == d {
Range::singleton(s[c].0)
} else {
Range::between(s[c].0, s[d].0 + 1)
};
deps.push((
dep_name,
if c == 0 && d == s_last_index {
Range::full()
} else if c == 0 {
Range::strictly_lower_than(s[d].0 + 1)
} else if d == s_last_index {
Range::higher_than(s[c].0)
} else if c == d {
Range::singleton(s[c].0)
if required {
Requirement::from_dependency(range)
} else {
Range::between(s[c].0, s[d].0 + 1)
Requirement::from_constraint(range)
},
))
}
Expand All @@ -224,10 +237,15 @@ pub fn registry_strategy<N: Package + Ord>(
.collect();

for ((name, ver), deps) in list_of_pkgid {
dependency_provider.add_dependencies(
dependency_provider.add_requirements(
name,
ver,
deps.unwrap_or_else(|| vec![(bad_name.clone(), Range::full())]),
deps.unwrap_or_else(|| {
vec![(
bad_name.clone(),
Requirement::from_dependency(Range::full()),
)]
}),
);
}

Expand Down Expand Up @@ -374,7 +392,7 @@ proptest! {
.versions(package)
.unwrap().collect();
let version = version_idx.get(&versions);
let dependencies: Vec<(u16, NumVS)> = match dependency_provider
let dependencies: Vec<_> = match dependency_provider
.get_dependencies(package, version)
.unwrap()
{
Expand All @@ -383,7 +401,7 @@ proptest! {
};
if !dependencies.is_empty() {
let dependency = dep_idx.get(&dependencies).0;
removed_provider.add_dependencies(
removed_provider.add_requirements(
**package,
**version,
dependencies.into_iter().filter(|x| x.0 != dependency),
Expand Down Expand Up @@ -442,7 +460,7 @@ proptest! {
Dependencies::Unknown => panic!(),
Dependencies::Known(deps) => deps,
};
smaller_dependency_provider.add_dependencies(n, v, deps)
smaller_dependency_provider.add_requirements(n, v, deps)
}
}
prop_assert!(
Expand All @@ -464,7 +482,7 @@ proptest! {
Dependencies::Unknown => panic!(),
Dependencies::Known(deps) => deps,
};
smaller_dependency_provider.add_dependencies(n, v, deps)
smaller_dependency_provider.add_requirements(n, v, deps)
}
}
prop_assert!(
Expand Down
5 changes: 3 additions & 2 deletions tests/sat_dependency_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,18 @@ impl<P: Package, VS: VersionSet> SatResolve<P, VS> {
Dependencies::Unknown => panic!(),
Dependencies::Known(d) => d,
};
for (p1, range) in &deps {
for (p1, requirement) in &deps {
let empty_vec = vec![];
let mut matches: Vec<varisat::Lit> = all_versions_by_p
.get(p1)
.unwrap_or(&empty_vec)
.iter()
.filter(|(v1, _)| range.contains(v1))
.filter(|(v1, _)| requirement.range.contains(v1))
.map(|(_, var1)| var1.positive())
.collect();
// ^ the `dep` is satisfied or
matches.push(var.negative());

// ^ `p` is not active
cnf.add_clause(&matches);
}
Expand Down
Loading

0 comments on commit 46def28

Please sign in to comment.