Skip to content

Commit

Permalink
feat(solver)!: Solve for optional solvables in addition to the root s…
Browse files Browse the repository at this point in the history
…olvable (#54)

* fix(solver): Call `clear` if level = 0 in `DecisionTracker::undo_until`

* fix(solver): Remove unneeded assert when processing package candidates

The requirement of ensuring that no decisions are made for any candidate
before the clauses for a package are added is unnecessary, since we now
perform propagation every time after adding any new clauses.

* fix(solver): Make `Solver::run_sat` solve for any solvable at any level

* feat(solver): Solve for optional solvables in addition to the root

* test(solver): Add tests for `Solver::solve_with_additional`

* fix(solver): Remove unused `DecisionTracker::is_empty`

* feat(solver)!: Rename `Problem`s to `Conflict`s

* feat(solver)!: Add `Problem` struct to describe solver input
  • Loading branch information
eviltak authored Aug 6, 2024
1 parent 31cf851 commit 0c77ba3
Show file tree
Hide file tree
Showing 8 changed files with 486 additions and 218 deletions.
7 changes: 4 additions & 3 deletions cpp/include/resolvo.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "resolvo_internal.h"

namespace resolvo {
using cbindgen_private::Problem;
using cbindgen_private::Requirement;

/**
Expand All @@ -30,8 +31,8 @@ inline Requirement requirement_union(VersionSetUnionId id) {
* stored in `result`. If the solve was unsuccesfull an error describing the reason is returned and
* the result vector will be empty.
*/
inline String solve(DependencyProvider &provider, Slice<Requirement> requirements,
Slice<VersionSetId> constraints, Vector<SolvableId> &result) {
inline String solve(DependencyProvider &provider, const Problem &problem,
Vector<SolvableId> &result) {
cbindgen_private::DependencyProvider bridge{
static_cast<void *>(&provider),
private_api::bridge_display_solvable,
Expand All @@ -50,7 +51,7 @@ inline String solve(DependencyProvider &provider, Slice<Requirement> requirement
};

String error;
cbindgen_private::resolvo_solve(&bridge, requirements, constraints, &error, &result);
cbindgen_private::resolvo_solve(&bridge, &problem, &error, &result);
return error;
}
} // namespace resolvo
45 changes: 31 additions & 14 deletions cpp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,28 +473,45 @@ impl<'d> resolvo::DependencyProvider for &'d DependencyProvider {
}
}

#[repr(C)]
pub struct Problem<'a> {
pub requirements: Slice<'a, Requirement>,
pub constraints: Slice<'a, VersionSetId>,
pub soft_requirements: Slice<'a, SolvableId>,
}

#[no_mangle]
#[allow(unused)]
pub extern "C" fn resolvo_solve(
provider: &DependencyProvider,
requirements: Slice<Requirement>,
constraints: Slice<VersionSetId>,
problem: &Problem,
error: &mut String,
result: &mut Vector<SolvableId>,
) -> bool {
let requirements = requirements
.into_iter()
.copied()
.map(Into::into)
.collect::<Vec<_>>();
let constraints = constraints
.into_iter()
.copied()
.map(Into::into)
.collect::<Vec<_>>();

let mut solver = resolvo::Solver::new(provider);
match solver.solve(requirements, constraints) {

let problem = resolvo::Problem {
requirements: problem
.requirements
.into_iter()
.copied()
.map(Into::into)
.collect(),
constraints: problem
.constraints
.into_iter()
.copied()
.map(Into::into)
.collect(),
soft_requirements: problem
.soft_requirements
.into_iter()
.copied()
.map(Into::into)
.collect(),
};

match solver.solve(problem) {
Ok(solution) => {
*result = solution.into_iter().map(Into::into).collect();
true
Expand Down
20 changes: 15 additions & 5 deletions cpp/tests/solve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,19 +216,27 @@ SCENARIO("Solve") {

auto c_1 = db.alloc_candidate("c", 1, {});

const auto d_1 = db.alloc_candidate("d", 1, {});

// Construct a problem to be solved by the solver
resolvo::Vector<resolvo::Requirement> requirements = {db.alloc_requirement("a", 1, 3)};
resolvo::Vector<resolvo::VersionSetId> constraints = {db.alloc_version_set("b", 1, 3),
db.alloc_version_set("c", 1, 3)};
resolvo::Vector<resolvo::VersionSetId> constraints = {
db.alloc_version_set("b", 1, 3),
db.alloc_version_set("c", 1, 3),
db.alloc_version_set("d", 2, 2),
};
resolvo::Vector soft_requirements{c_1, d_1};

// Solve the problem
resolvo::Vector<resolvo::SolvableId> result;
resolvo::solve(db, requirements, constraints, result);
resolvo::Problem problem = {requirements, constraints, soft_requirements};
resolvo::solve(db, problem, result);

// Check the result
REQUIRE(result.size() == 2);
REQUIRE(result.size() == 3);
REQUIRE(result[0] == a_2);
REQUIRE(result[1] == b_2);
REQUIRE(result[2] == c_1);
}

SCENARIO("Solve Union") {
Expand Down Expand Up @@ -264,7 +272,9 @@ SCENARIO("Solve Union") {

// Solve the problem
resolvo::Vector<resolvo::SolvableId> result;
resolvo::solve(db, requirements, constraints, result);
resolvo::Problem problem = {requirements, constraints, {}};
resolvo::solve(db, problem, result);
;

// Check the result
REQUIRE(result.size() == 4);
Expand Down
Loading

0 comments on commit 0c77ba3

Please sign in to comment.