Strategical decision making in a DependencyProvider

In PubGrub, decision making is the process of choosing the next package and version that will be appended to the solution being built. Every time such a decision must be made, potential valid packages are preselected with corresponding valid ranges of versions. Then, there is some freedom regarding which of those package versions to choose.

The strategy employed to choose such package and version cannot change the existence of a solution or not, but can drastically change the performance of the solver, or the properties of the solution.

In our implementation of PubGrub, decision making responsibility is divided into two pieces. The resolver takes care of making a preselection for potential packages and corresponding ranges of versions. Then it's the dependency provider that has the freedom of employing the strategy of picking a single package version through prioritize and choose_version.

Picking a package

Potential packages basically are packages that appeared in the dependencies of a package we've already added to the solution. So once a package appear in potential packages, it will continue to be proposed as such until we pick it, or a conflict shows up and the solution is backtracked before needing it.

Imagine that one such potential package is limited to a range containing no existing version, we are heading directly to a conflict! So we are better dealing with that conflict as soon as possible, instead of delaying it for later since we will have to backtrack anyway. Consequently, we always want to pick first a conflictual potential package with no valid version. Similarly, potential packages with only one valid version give us no choice and limit options going forward, so we might want to pick such potential packages before others with more version choices. Generalizing this strategy to picking the potential package with the lowest number of valid versions is a rather good heuristic performance-wise. This strategy is the one employed by the OfflineDependencyProvider. You can use the PackageResolutionStatistics passed into prioritize for a heuristic for conflicting-ness: The more conflict a package had, the higher its priority should be.

Picking a version

In general, letting the dependency provider choose a version in choose_version provides a great deal of flexibility and enables things like

  • choosing the newest versions,
  • choosing the oldest versions,
  • choosing already downloaded versions,
  • choosing versions specified in a lock file,

and many other desirable behaviors for the resolver, controlled directly by the dependency provider.