All notable changes to this project will be documented in this file.
DependencyConstraints is now an opaque type that retains the ordering of the dependencies across platforms. This fixes
unstable resolutions across platform (pubgrub-rs#373). DependencyConstraints can be
constructed from an iterator. It is currently backed by a Vec internally.
SelectedDependencies is now an opaque type that support iteration and get().
0.3.0 - 2025-02-12 - (diff with 0.2.1)
PubGrub 0.3 has a more flexible interface and speeds resolution significantly. The public API is very different now, we
recommend starting the migration by implementing the new DependencyProvider interface following the
Guide.
All public interfaces are now in the root of the crate.
In the main interface, DependencyProvider, choose_package_version was split into two methods: prioritize
for choosing which package to decide next by assigning a priority to each package, and choose_version. The generic
parameters became associated types. The version set is configurable by an associated type.
Dependencies gained a generic parameter for custom incompatibility type outside version conflicts, such as packages
not available for the current platform or permission errors. This type is on DependencyProvider as
DependencyProvider::M.
pubgrub::range::Range now lives in its own crate as version_ranges::Ranges. A Version can be almost any
ordered type now, it only needs to support set operations through VersionSet.
At a glance, this is the new DependencyProvider interface:
pub trait DependencyProvider {
type P: Package;
type V: Debug + Display + Clone + Ord;
type VS: VersionSet<V = Self::V>;
type M: Eq + Clone + Debug + Display;
type Priority: Ord + Clone;
type Err: Error + 'static;
fn prioritize(
&self,
package: &Self::P,
range: &Self::VS,
package_conflicts_counts: &PackageResolutionStatistics,
) -> Self::Priority;
fn choose_version(
&self,
package: &Self::P,
range: &Self::VS,
) -> Result<Option<Self::V>, Self::Err>;
fn get_dependencies(
&self,
package: &Self::P,
version: &Self::V,
) -> Result<Dependencies<Self::P, Self::VS, Self::M>, Self::Err>;
}0.2.1 - 2021-06-30 - (diff with 0.2.0)
This release is focused on performance improvements and code readability, without any change to the public API.
The code tends to be simpler around tricky parts of the algorithm such as conflict resolution. Some data structures have been rewritten (with no unsafe) to lower memory usage. Depending on scenarios, version 0.2.1 is 3 to 8 times faster than 0.2.0. As an example, solving all elm package versions existing went from 580ms to 175ms on my laptop. While solving a specific subset of packages from crates.io went from 2.5s to 320ms on my laptop.
Below are listed all the important changes in the internal parts of the API.
- New
SmallVecdata structure (with no unsafe) using fixed size arrays for up to 2 entries. - New
SmallMapdata structure (with no unsafe) using fixed size arrays for up to 2 entries. - New
Arenadata structure (with no unsafe) backed by aVecand indexed withId<T>whereTis phantom data.
- Updated the
large_casebenchmark to run with both u16 and string package identifiers in registries. - Use the new
Arenafor the incompatibility store, and use itsId<T>identifiers to reference incompatibilities instead of full owned copies in theincompatibilitiesfield of the solverState. - Save satisfier indices of each package involved in an incompatibility when looking for its satisfier. This speeds up the search for the previous satisfier.
- Early unit propagation loop restart at the first conflict found instead of continuing evaluation for the current package.
- Index incompatibilities by package in a hash map instead of using a vec.
- Keep track of already contradicted incompatibilities in a
Setuntil the next backtrack to speed up unit propagation. - Unify
historyandmemoryinpartial_solutionunder a unique hash map indexed by packages. This should speed up access to relevan terms in conflict resolution.
0.2.0 - 2020-11-19 - (diff with 0.1.0)
This release brings many important improvements to PubGrub. The gist of it is:
- A bug in the algorithm's implementation was fixed.
- The solver is now implemented in a
resolvefunction taking as argument an implementer of theDependencyProvidertrait, which has more control over the decision making process. - End-to-end property testing of large synthetic registries was added.
- More than 10x performance improvement.
- Links to code items in the code documentation.
- New
"serde"feature that allows serializing some library types, useful for making simple reproducible bug reports. - New variants for
error::PubGrubErrorwhich areDependencyOnTheEmptySet,SelfDependency,ErrorChoosingPackageVersionandErrorInShouldCancel. - New
type_alias::Mapdefined asrustc_hash::FxHashMap. - New
type_alias::SelectedDependencies<P, V>defined asMap<P, V>. - The types
DependenciesandDependencyConstraintswere introduced to clarify intent. - New function
choose_package_with_fewest_versionsto help implement thechoose_package_versionmethod of aDependencyProvider. - Implement
FromStrforSemanticVersion. - Add the
VersionParseErrortype for parsing of semantic versions.
- The
Solvertrait was replaced by aDependencyProvidertrait which now must implement achoose_package_versionmethod instead oflist_available_versions. So it now has the ability to choose a package in addition to a version. TheDependencyProvideralso has a new optional methodshould_cancelthat may be used to stop the solver if needed. - The
choose_package_versionandget_dependenciesmethods of theDependencyProvidertrait now take an immutable reference toself. Interior mutability can be used by implementor if mutability is needed. - The
Solver.runmethod was thus replaced by a free functionsolver::resolvetaking a dependency provider as first argument. - The
OfflineSolveris thus replaced by anOfflineDependencyProvider. SemanticVersionnow takesu32instead ofusizefor its 3 parts.NumberVersionnow usesu32instead ofusize.
ErrorRetrievingVersionsvariant oferror::PubGrubError.
benches/large_case.rsenables benchmarking of serialized registries of packages.examples/caching_dependency_provider.rsan example dependency provider caching dependencies.PackageTerm<P, V> = (P, Term<V>)new type alias for readability.Memory.term_intersection_for_package(&mut self, package: &P) -> Option<&Term<V>>- New types were introduces for conflict resolution in
internal::partial_solutionto clarify the intent and return values of some functions. Those types areDatedAssignmentandSatisfierAndPreviousHistory. PartialSolution.term_intersection_for_packagecalling the same function from itsmemory.- New property tests for ranges:
negate_contains_opposite,intesection_contains_bothandunion_contains_either. - A large synthetic test case was added in
test-examples/. - A new test example
double_choiceswas added for the detection of a bug (fixed) in the implementation. - Property testing of big synthetic datasets was added in
tests/proptest.rs. - Comparison of PubGrub solver and a SAT solver
was added with
tests/sat_dependency_provider.rs. - Other regression and unit tests were added to
tests/tests.rs.
- CI workflow was improved (
./github/workflows/), including a check for Conventional Commits and Clippy for source code linting. - Using SPDX license identifiers instead of MPL-2.0 classic file headers.
State.incompatibilitiesis now wrapped inside aRc.DecisionLevel(u32)is used in place ofusizefor partial solution decision levels.State.conflict_resolutionnow also returns the almost satisfied package to avoid an unnecessary call toself.partial_solution.relation(...)after conflict resolution.Kind::NoVersionrenamed toKind::NoVersionsand all other usage ofnoversionhas been changed tono_versions.- Variants of the
incompatibility::Relationenum have changed. - Incompatibility now uses a deterministic hasher to store packages in its hash map.
incompatibility.relation(...)now takes a function as argument to avoid computations of unnecessary terms intersections.Memorynow uses a deterministic hasher instead of the default one.memory::PackageAssignmentsis now an enum instead of a struct.- Derivations in a
PackageAssignmentskeep a precomputed intersection of derivation terms. potential_packagesmethod now returns aRangeinstead of aTermfor the versions constraint of each package.PartialSolution.relationnow takes&mut selfinstead of&selfto be able to store computation of terms intersection.Term.accept_versionwas renamedTerm.contains.- The
satisfied_byandcontradicted_bymethods of aTermnow directly takes a reference to the intersection of other terms. Same forrelation_with.
termfield of anAssignment::Derivationvariant.Memory.all_termsmethod was removed.Memory.remove_decisionmethod was removed in favor of a check before usingMemory.add_decision.PartialSolutionmethodspick_packageandpick_versionhave been removed since control was given back to the dependency provider to choose a package version.PartialSolutionmethodsremove_last_decisionandsatisfies_any_ofwere removed in favor of a preventive check before callingadd_decision.Term.is_negative.
- Prior cause computation (
incompatibility::prior_cause) now uses the intersection of package terms instead of their union, which was an implementation error.
0.1.0 - 2020-10-01
README.mdas the home page of this repository.LICENSE, code is provided under the MPL 2.0 license.Cargo.tomlconfiguration of this Rust project.src/containing all the source code for this first implementation of PubGrub in Rust.tests/containing test end-to-end examples.examples/other examples, not in the form of tests..gitignoreconfigured for a Rust project..github/workflows/CI to automatically build, test and document on push and pull requests.