/// <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); }
public void TestIsConflict() { decisions.Decide(1, 1, defaultRule); decisions.Decide(-2, 1, defaultRule); Assert.IsTrue(decisions.IsConflict(-1)); Assert.IsFalse(decisions.IsConflict(1)); Assert.IsTrue(decisions.IsConflict(2)); Assert.IsFalse(decisions.IsConflict(-2)); Assert.IsFalse(decisions.IsConflict(3)); }