All notable changes to this project will be documented in this file.
Unreleased (diff)
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
SmallVec
data structure (with no unsafe) using fixed size arrays for up to 2 entries. - New
SmallMap
data structure (with no unsafe) using fixed size arrays for up to 2 entries. - New
Arena
data structure (with no unsafe) backed by aVec
and indexed withId<T>
whereT
is phantom data.
- Updated the
large_case
benchmark to run with both u16 and string package identifiers in registries. - Use the new
Arena
for the incompatibility store, and use itsId<T>
identifiers to reference incompatibilities instead of full owned copies in theincompatibilities
field 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
Set
until the next backtrack to speed up unit propagation. - Unify
history
andmemory
inpartial_solution
under 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
resolve
function taking as argument an implementer of theDependencyProvider
trait, 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::PubGrubError
which areDependencyOnTheEmptySet
,SelfDependency
,ErrorChoosingPackageVersion
andErrorInShouldCancel
. - New
type_alias::Map
defined asrustc_hash::FxHashMap
. - New
type_alias::SelectedDependencies<P, V>
defined asMap<P, V>
. - The types
Dependencies
andDependencyConstraints
were introduced to clarify intent. - New function
choose_package_with_fewest_versions
to help implement thechoose_package_version
method of aDependencyProvider
. - Implement
FromStr
forSemanticVersion
. - Add the
VersionParseError
type for parsing of semantic versions.
- The
Solver
trait was replaced by aDependencyProvider
trait which now must implement achoose_package_version
method instead oflist_available_versions
. So it now has the ability to choose a package in addition to a version. TheDependencyProvider
also has a new optional methodshould_cancel
that may be used to stop the solver if needed. - The
choose_package_version
andget_dependencies
methods of theDependencyProvider
trait now take an immutable reference toself
. Interior mutability can be used by implementor if mutability is needed. - The
Solver.run
method was thus replaced by a free functionsolver::resolve
taking a dependency provider as first argument. - The
OfflineSolver
is thus replaced by anOfflineDependencyProvider
. SemanticVersion
now takesu32
instead ofusize
for its 3 parts.NumberVersion
now usesu32
instead ofusize
.
ErrorRetrievingVersions
variant oferror::PubGrubError
.
benches/large_case.rs
enables benchmarking of serialized registries of packages.examples/caching_dependency_provider.rs
an 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_solution
to clarify the intent and return values of some functions. Those types areDatedAssignment
andSatisfierAndPreviousHistory
. PartialSolution.term_intersection_for_package
calling the same function from itsmemory
.- New property tests for ranges:
negate_contains_opposite
,intesection_contains_both
andunion_contains_either
. - A large synthetic test case was added in
test-examples/
. - A new test example
double_choices
was 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.incompatibilities
is now wrapped inside aRc
.DecisionLevel(u32)
is used in place ofusize
for partial solution decision levels.State.conflict_resolution
now also returns the almost satisfied package to avoid an unnecessary call toself.partial_solution.relation(...)
after conflict resolution.Kind::NoVersion
renamed toKind::NoVersions
and all other usage ofnoversion
has been changed tono_versions
.- Variants of the
incompatibility::Relation
enum 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.Memory
now uses a deterministic hasher instead of the default one.memory::PackageAssignments
is now an enum instead of a struct.- Derivations in a
PackageAssignments
keep a precomputed intersection of derivation terms. potential_packages
method now returns aRange
instead of aTerm
for the versions constraint of each package.PartialSolution.relation
now takes&mut self
instead of&self
to be able to store computation of terms intersection.Term.accept_version
was renamedTerm.contains
.- The
satisfied_by
andcontradicted_by
methods of aTerm
now directly takes a reference to the intersection of other terms. Same forrelation_with
.
term
field of anAssignment::Derivation
variant.Memory.all_terms
method was removed.Memory.remove_decision
method was removed in favor of a check before usingMemory.add_decision
.PartialSolution
methodspick_package
andpick_version
have been removed since control was given back to the dependency provider to choose a package version.PartialSolution
methodsremove_last_decision
andsatisfies_any_of
were 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.md
as the home page of this repository.LICENSE
, code is provided under the MPL 2.0 license.Cargo.toml
configuration 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..gitignore
configured for a Rust project..github/workflows/
CI to automatically build, test and document on push and pull requests.