/// <summary> /// Propagates a decision on a literal to all rules watching the literal. /// </summary> /// <remarks> /// If a decision, e.g. +A has been made, then all rules containing -A, e.g. /// (-A|+B|+C) now need to satisfy at least one of the other literals, so /// that the rule as a whole becomes true, since with +A applied the rule /// is now (false|+B|+C) so essentially (+B|+C). /// This means that all rules watching the literal -A need to be updated to /// watch 2 other literals which can still be satisfied instead. So literals /// that conflict with previously made decisions are not an option. /// Alternatively it can occur that a unit clause results: e.g. if in the /// above example the rule was (-A|+B), then A turning true means that /// B must now be decided true as well. /// </remarks> /// <param name="decidedLiteral">The literal which was decided.</param> /// <param name="level">The level at which the decision took place and at which all resulting decisions should be made.</param> /// <param name="decisions">Used to check previous decisions and to register decisions resulting from propagation.</param> /// <returns>If a conflict is found the conflicting rule is returned.</returns> public Rule PropagateLiteral(int decidedLiteral, int level, Decisions decisions) { // we invert the decided literal here, example: // A was decided => (-A|B) now requires B to be true, so we look for // rules which are fulfilled by -A, rather than A. // This means finding out the conflicts or requires. var literal = -decidedLiteral; if (!watchChains.TryGetValue(literal, out LinkedList <RuleWatchNode> chain)) { return(null); } foreach (var node in chain.ToArray()) { var otherWatch = node.GetOtherWatch(literal); if (!node.GetRule().Enable || decisions.IsSatisfy(otherWatch)) { continue; } var ruleLiterals = node.GetRule().GetLiterals(); var alternativeLiterals = Arr.Filter(ruleLiterals, (ruleLiteral) => { // Guaranteed selection decision is not at the same time // as Watch1 and Watch2, guaranteeing no conflict. return(literal != ruleLiteral && otherWatch != ruleLiteral && !decisions.IsConflict(ruleLiteral)); }); if (alternativeLiterals.Length > 0) { var toLiteral = alternativeLiterals[0]; if (!watchChains.TryGetValue(toLiteral, out LinkedList <RuleWatchNode> toChain)) { watchChains[toLiteral] = toChain = new LinkedList <RuleWatchNode>(); } node.MoveWatch(literal, toLiteral); chain.Remove(node); toChain.AddFirst(node); continue; } if (decisions.IsConflict(otherWatch)) { return(node.GetRule()); } decisions.Decide(otherWatch, level, node.GetRule()); } return(null); }
/// <summary> /// Resolve the requires of the requested. /// </summary> /// <param name="request">The request instance.</param> /// <param name="ignorePlantform">Whether is ignore plantform check.</param> /// <returns>An array of operation.</returns> public IOperation[] Solve(Request request, bool ignorePlantform = false) { jobs = request.GetJobs(); SetupInstalledMap(); rules = ruleSetGenerator.GetRulesFor(jobs, installedMap, ignorePlantform); CheckForRootRequiresProblems(ignorePlantform); decisions = new Decisions(pool); watchGraph = new RuleWatchGraph(); learnedWhy.Clear(); learnedPool.Clear(); branches.Clear(); foreach (var rule in rules) { watchGraph.Add(rule); } SetupAssertionRuleDecisions(); io.WriteError("Resolving requires through SAT", true, Verbosities.Debug); stopwatch.Restart(); stopwatch.Start(); RunSAT(); io.WriteError(string.Empty, true, Verbosities.Debug); io.WriteError($"Dependency resolution completed in {stopwatch.Elapsed.TotalSeconds.ToString("0.00")} seconds", true, Verbosities.Debug); // If we don't make a decision about the packages we have // installed, then we think these packages will be uninstall. foreach (var item in installedMap) { var packageId = item.Key; if (decisions.IsUndecided(packageId)) { decisions.Decide(-packageId, 1, null); } } if (problems.Count > 0) { throw new SolverProblemsException(problems, installedMap); } var transaction = new Transaction(policy, pool, installedMap, decisions); return(transaction.GetOperations()); }
// can be used as interface to update all decision at once public void UpdateDecisions(uint frameCount = 3600) { // we assume 3600 is enough for all frame intervals decisions_.Decide(frameCount); decisions_.ExecuteDecision(frameCount); }
public void TestDecide() { Assert.AreEqual(0, decisions.Count); decisions.Decide(1, 1, defaultRule); Assert.AreEqual(1, decisions.Count); Assert.IsTrue(decisions.IsDecided(1)); }