Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specialize range operations for better performance #25

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2b65107
Initial divergences from upstream (#1)
zanieb Dec 1, 2023
b82ece6
Add GitHub workflow to automatically tag each commit on `main` (#2)
zanieb Nov 16, 2023
b2db89b
Fix-ups to tag generating action (#3)
zanieb Nov 16, 2023
b10f7f5
Add an `UnusableDependencies` incompatibility kind (#4)
zanieb Nov 16, 2023
bea5e13
Update `Range` to match upstream (#5)
zanieb Dec 1, 2023
ec11f77
Add `DerivationTree.packages() -> HashSet<&P>` (#11)
zanieb Dec 8, 2023
4ddd38a
Avoid loss of data in Range.simplify (#13)
zanieb Dec 12, 2023
f869250
Move formatting of explanations into the report formatter (#19)
zanieb Jan 12, 2024
5f4c37b
Consolidate `UnusableDependencies` into a generic `Unavailable` incom…
zanieb Jan 25, 2024
f246be7
Add a `reason` to the `NoVersions` incompatibility (#22)
zanieb Feb 5, 2024
b5ead05
use impl IntoIterator to avoide clones (#24)
charliermarsh Feb 22, 2024
ce20be0
Use binary search for `Range::contains`
konstin Mar 5, 2024
88d8d8c
Avoid cloning and dropping the term in prior_cause
konstin Mar 5, 2024
60ead6b
Simplify contains
konstin Mar 7, 2024
85bedc6
Specialize union code
Eh2406 Mar 11, 2024
c213235
remove a redundant check and reuse helper
Eh2406 Mar 11, 2024
3fc2b10
Specialize is_disjoint
Eh2406 Mar 11, 2024
d92c042
simplify and add tests for is_disjoint
Eh2406 Mar 11, 2024
45ca156
Specialize subset_of
Eh2406 Mar 11, 2024
4a32b76
simplify and add tests for subset_of
Eh2406 Mar 11, 2024
6715dc7
Specialize range operations for better performance
konstin Mar 11, 2024
08830f6
add tests and use in more places
Eh2406 Mar 11, 2024
74f61fb
Fix clippy lints
konstin Mar 11, 2024
1965345
Add `Range::is_disjoint()` symmetry proptest
konstin Mar 13, 2024
f7db1f7
replace a complement with is_disjoint
Eh2406 Mar 13, 2024
0e1d596
one fewer complement using intersection
Eh2406 Mar 13, 2024
10ab631
use the symmetry of set functions
Eh2406 Mar 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/permaref.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Automatically creates a tag for each commit to `main` so when we rebase
# changes on top of the upstream, we retain permanent references to each
# previous commit so they are not orphaned and eventually deleted.
name: Create permanent reference

on:
push:
branches:
- "main"

jobs:
create-permaref:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Get the permanent ref number
id: get_version
run: |
# Enable pipefail so git command failures do not result in null versions downstream
set -x

echo "LAST_PERMA_NUMBER=$(\
git ls-remote --tags --refs --sort="v:refname" \
https://github.com/zanieb/pubgrub.git | grep "tags/perma-" | tail -n1 | sed 's/.*\/perma-//' \
)" >> $GITHUB_OUTPUT

- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"

- name: Create and push the new tag
run: |
TAG="perma-$((LAST_PERMA_NUMBER + 1))"
git tag -a "$TAG" -m 'Automatically created on push to `main`'
git push origin "$TAG"
env:
LAST_PERMA_NUMBER: ${{ steps.get_version.outputs.LAST_PERMA_NUMBER }}
87 changes: 0 additions & 87 deletions examples/caching_dependency_provider.rs

This file was deleted.

109 changes: 104 additions & 5 deletions examples/unsat_root_message_no_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use pubgrub::error::PubGrubError;
use pubgrub::range::Range;
use pubgrub::report::Reporter;
use pubgrub::report::{Derived, Reporter};
use pubgrub::solver::{resolve, OfflineDependencyProvider};
use pubgrub::version::SemanticVersion;

Expand Down Expand Up @@ -66,18 +66,18 @@ impl ReportFormatter<Package, Range<SemanticVersion>> for CustomReportFormatter
External::NotRoot(package, version) => {
format!("we are solving dependencies of {package} {version}")
}
External::NoVersions(package, set) => {
External::NoVersions(package, set, _) => {
if set == &Range::full() {
format!("there is no available version for {package}")
} else {
format!("there is no version of {package} in {set}")
}
}
External::UnavailableDependencies(package, set) => {
External::Unavailable(package, set, reason) => {
if set == &Range::full() {
format!("dependencies of {package} are unavailable")
format!("dependencies of {package} are unavailable because {reason}")
} else {
format!("dependencies of {package} at version {set} are unavailable")
format!("dependencies of {package} at version {set} are unavailable because {reason}")
}
}
External::FromDependencyOf(package, package_set, dependency, dependency_set) => {
Expand All @@ -101,6 +101,105 @@ impl ReportFormatter<Package, Range<SemanticVersion>> for CustomReportFormatter
}
}
}

/// Simplest case, we just combine two external incompatibilities.
fn explain_both_external(
&self,
external1: &External<Package, Range<SemanticVersion>>,
external2: &External<Package, Range<SemanticVersion>>,
current_terms: &Map<Package, Term<Range<SemanticVersion>>>,
) -> String {
// TODO: order should be chosen to make it more logical.
format!(
"Because {} and {}, {}.",
self.format_external(external1),
self.format_external(external2),
self.format_terms(current_terms)
)
}

/// Both causes have already been explained so we use their refs.
fn explain_both_ref(
&self,
ref_id1: usize,
derived1: &Derived<Package, Range<SemanticVersion>>,
ref_id2: usize,
derived2: &Derived<Package, Range<SemanticVersion>>,
current_terms: &Map<Package, Term<Range<SemanticVersion>>>,
) -> String {
// TODO: order should be chosen to make it more logical.
format!(
"Because {} ({}) and {} ({}), {}.",
self.format_terms(&derived1.terms),
ref_id1,
self.format_terms(&derived2.terms),
ref_id2,
self.format_terms(current_terms)
)
}

/// One cause is derived (already explained so one-line),
/// the other is a one-line external cause,
/// and finally we conclude with the current incompatibility.
fn explain_ref_and_external(
&self,
ref_id: usize,
derived: &Derived<Package, Range<SemanticVersion>>,
external: &External<Package, Range<SemanticVersion>>,
current_terms: &Map<Package, Term<Range<SemanticVersion>>>,
) -> String {
// TODO: order should be chosen to make it more logical.
format!(
"Because {} ({}) and {}, {}.",
self.format_terms(&derived.terms),
ref_id,
self.format_external(external),
self.format_terms(current_terms)
)
}

/// Add an external cause to the chain of explanations.
fn and_explain_external(
&self,
external: &External<Package, Range<SemanticVersion>>,
current_terms: &Map<Package, Term<Range<SemanticVersion>>>,
) -> String {
format!(
"And because {}, {}.",
self.format_external(external),
self.format_terms(current_terms)
)
}

/// Add an already explained incompat to the chain of explanations.
fn and_explain_ref(
&self,
ref_id: usize,
derived: &Derived<Package, Range<SemanticVersion>>,
current_terms: &Map<Package, Term<Range<SemanticVersion>>>,
) -> String {
format!(
"And because {} ({}), {}.",
self.format_terms(&derived.terms),
ref_id,
self.format_terms(current_terms)
)
}

/// Add an already explained incompat to the chain of explanations.
fn and_explain_prior_and_external(
&self,
prior_external: &External<Package, Range<SemanticVersion>>,
external: &External<Package, Range<SemanticVersion>>,
current_terms: &Map<Package, Term<Range<SemanticVersion>>>,
) -> String {
format!(
"And because {} and {}, {}.",
self.format_external(prior_external),
self.format_external(external),
self.format_terms(current_terms)
)
}
}

fn main() {
Expand Down
9 changes: 5 additions & 4 deletions src/internal/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::internal::partial_solution::{DecisionLevel, PartialSolution};
use crate::internal::small_vec::SmallVec;
use crate::package::Package;
use crate::report::DerivationTree;
use crate::type_aliases::{DependencyConstraints, Map, Set};
use crate::type_aliases::{Map, Set};
use crate::version_set::VersionSet;

/// Current state of the PubGrub algorithm.
Expand All @@ -25,7 +25,8 @@ pub struct State<P: Package, VS: VersionSet, Priority: Ord + Clone> {
root_package: P,
root_version: VS::V,

incompatibilities: Map<P, Vec<IncompId<P, VS>>>,
/// The set of incompatibilities for each package.
pub incompatibilities: Map<P, Vec<IncompId<P, VS>>>,

/// Store the ids of incompatibilities that are already contradicted.
/// For each one keep track of the decision level when it was found to be contradicted.
Expand Down Expand Up @@ -82,12 +83,12 @@ impl<P: Package, VS: VersionSet, Priority: Ord + Clone> State<P, VS, Priority> {
&mut self,
package: P,
version: VS::V,
deps: &DependencyConstraints<P, VS>,
deps: impl IntoIterator<Item = (P, 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| {
.alloc_iter(deps.into_iter().map(|dep| {
Incompatibility::from_dependency(
package.clone(),
VS::singleton(version.clone()),
Expand Down
Loading