From c1f69a64fd5070723ef425cc1255cde2a28966ad Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 1 Aug 2024 15:51:37 +0900 Subject: solver3: Introduce new Assume() and Enqueue() helpers and use them These are taken roughly from the MiniSAT paper. We still have a bit to go in actually encoding all clauses so the reasons are still variables, and Assume() isn't fully working yet. Adjust the existing Install()/Reject() code to use these functions, we already see additional lines in the log that we failed to log before, and this ensures more consistency. This is sort of still the wrong direction: Install()/Reject() do the propagation too; but that is tbd. --- apt-pkg/solver3.cc | 64 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 23 deletions(-) (limited to 'apt-pkg/solver3.cc') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index 5065b9a87..a21af12f9 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -304,6 +304,35 @@ bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg) const pkgObsolete[pkg->ID] = 2; return true; } +bool APT::Solver::Assume(Var var, bool decision, Var reason) +{ + choices.push_back(solved.size()); + return Enqueue(var, decision, std::move(reason)); +} + +bool APT::Solver::Enqueue(Var var, bool decision, Var reason) +{ + auto &state = (*this)[var]; + auto decisionCast = decision ? Decision::MUST : Decision::MUSTNOT; + + if (state.decision != Decision::NONE) + { + if (state.decision != decisionCast) + return _error->Error("Conflict: %s -> %s%s but %s", WhyStr(reason).c_str(), decision ? "" : "not ", var.toString(cache).c_str(), WhyStr(var).c_str()); + return true; + } + + state.decision = decisionCast; + state.depth = depth(); + state.reason = reason; + + if (unlikely(debug >= 1)) + std::cerr << "[" << depth() << "] " << (decision ? "Install" : "Reject") << ":" << var.toString(cache) << " (" << WhyStr(state.reason) << ")\n"; + + solved.push_back(Solved{var, std::nullopt}); + + return true; +} bool APT::Solver::Install(pkgCache::PkgIterator Pkg, Var reason, Group group) { @@ -329,10 +358,8 @@ bool APT::Solver::Install(pkgCache::PkgIterator Pkg, Var reason, Group group) } // Note decision - if (unlikely(debug >= 1)) - std::cerr << "[" << depth() << "] Install:" << Pkg.FullName() << " (" << WhyStr(reason) << ")\n"; - (*this)[Pkg] = {reason, depth(), Decision::MUST}; - solved.push_back(Solved{Var(Pkg), std::nullopt}); + if (not Enqueue(Var(Pkg), true, reason)) + return false; // Insert the work item. Work workItem{Var(Pkg), depth(), group}; @@ -380,15 +407,10 @@ bool APT::Solver::Install(pkgCache::VerIterator Ver, Var reason, Group group) WhyStr(Var(otherVer)).c_str()); // Note decision - if (unlikely(debug >= 1)) - std::cerr << "[" << depth() << "] Install:" << Ver.ParentPkg().FullName() << "=" << Ver.VerStr() << " (" << WhyStr(reason) << ")\n"; - (*this)[Ver] = {reason, depth(), Decision::MUST}; - solved.push_back(Solved{Var(Ver), std::nullopt}); - if ((*this)[Ver.ParentPkg()].decision != Decision::MUST) - { - (*this)[Ver.ParentPkg()] = {Var(Ver), depth(), Decision::MUST}; - solved.push_back(Solved{Var(Ver.ParentPkg()), std::nullopt}); - } + if (not Enqueue(Var(Ver), true, reason)) + return false; + if (not Enqueue(Var(Ver.ParentPkg()), true, Var(Ver))) + return false; for (auto OV = Ver.ParentPkg().VersionList(); not OV.end(); ++OV) { @@ -423,10 +445,8 @@ bool APT::Solver::Reject(pkgCache::PkgIterator Pkg, Var reason, Group group) return _error->Error("Conflict: %s -> not %s but %s", WhyStr(reason).c_str(), Pkg.FullName().c_str(), WhyStr(Var(Pkg)).c_str()); // Reject the package and its versions. - if (unlikely(debug >= 1)) - std::cerr << "[" << depth() << "] Reject:" << Pkg.FullName() << " (" << WhyStr(reason) << ")\n"; - (*this)[Pkg] = {reason, depth(), Decision::MUSTNOT}; - solved.push_back(Solved{Var(Pkg), std::nullopt}); + if (not Enqueue(Var(Pkg), false, reason)) + return false; for (auto ver = Pkg.VersionList(); not ver.end(); ver++) if (not Reject(ver, Var(Pkg), group)) return false; @@ -452,10 +472,8 @@ bool APT::Solver::Reject(pkgCache::VerIterator Ver, Var reason, Group group) WhyStr(Var(Ver)).c_str()); // Mark the package as rejected and propagate up as needed. - if (unlikely(debug >= 1)) - std::cerr << "[" << depth() << "] Reject:" << Ver.ParentPkg().FullName() << "=" << Ver.VerStr() << " (" << WhyStr(reason) << ")\n"; - (*this)[Ver] = {reason, depth(), Decision::MUSTNOT}; - solved.push_back(Solved{Var(Ver), std::nullopt}); + if (not Enqueue(Var(Ver), false, reason)) + return false; if (auto pkg = Ver.ParentPkg(); (*this)[pkg].decision != Decision::MUSTNOT) { bool anyInstallable = false; @@ -478,8 +496,8 @@ bool APT::Solver::Reject(pkgCache::VerIterator Ver, Var reason, Group group) } else if ((*this)[Ver.ParentPkg()].decision != Decision::MUSTNOT) // Last installable invalidated { - (*this)[Ver.ParentPkg()] = {Var(Ver), depth(), Decision::MUSTNOT}; - solved.push_back(Solved{Var(Ver), std::nullopt}); + if (not Enqueue(Var(Ver.ParentPkg()), false, Var(Ver))) + return false; } } -- cgit v1.2.3-70-g09d2