/// <summary> /// выбирает неназначенный литерал, добавляет его в присваивание и помечает как решающий. /// </summary> /// <param name="cnf"></param> public void Decide(CNF cnf) { var literal = cnf.Dlis(); var addLit = new Literal(literal.Var, false); addLit.SetValue(false); assigmentStack.Push(new AssignmentItem(addLit, true));//literal, true)); decideCount++; }
/// <summary> /// DPLL - работает используя полный перебор. /// Завершается sat - если удалось подобрать значения при которых нет ни одного ложного дизъюнкта. /// При обнаружении конфликта возвращаемся к хронологически последнему ветвлению. /// </summary> /// <param name="cnf">решаемый кнф</param> /// <returns>sat/unsat</returns> static public bool SolveDpll(CNF cnf) { var assignment = new Assignment(); uint maxWhileCount = uint.MaxValue; uint l = 0; //существует хотя бы один не назначенный литерал в cnf while (cnf.IsAnyUnknownLiteral()) { //существует хотя бы один еденичный дизъюнкт while (cnf.IsAnyUnitClause()) { assignment.UnitPropagate(cnf); while (cnf.IsUnsat()) { //есть хоть один рещающий литерал, то откатываемся назад if (assignment.IsAnyDecideLiteral()) { assignment.BackjumpDpll(cnf); } else//правило Fail { return(false); } } } if (cnf.IsAnyUnknownLiteral()) { assignment.Decide(cnf); } else { break; } if (l > maxWhileCount) { throw new Exception("Превышена максимально допустимая глубина цикличности."); } l++; } Console.WriteLine("CNF"); foreach (var cl in cnf.Clauses) { Console.WriteLine(cl.ToString()); } Console.WriteLine(assignment.GetStatistics()); Console.WriteLine("Variables"); Console.WriteLine(cnf.VariablesValueToString()); return(true); }
/// <summary> /// единичный дизъюнкт с неназначенным литералом, верен если этот литерал верен /// </summary> /// <param name="cnf"></param> public void UnitPropagate(CNF cnf) { foreach (var cl in cnf.Clauses) { if (cl.TryGetUnit(out var lit)) { lit.SetValue(true); var literal = new Literal(lit.Var, !lit.IsPositive); assigmentStack.Push(new AssignmentItem(literal, false)); unitPropagateCount++; return; } } }
/// <summary> /// Xронологический возврат /// </summary> public void BackjumpDpll(CNF cnf) { bool isFound = false; while (!isFound) { if (!assigmentStack.TryPop(out var popItem)) { break; //вообще исключение следует генерить } if (popItem.IsDecide) { var lit = new Literal(popItem.Literal.Var, true);//!popItem.Literal.isPositive); lit.SetValue(false); assigmentStack.Push(new AssignmentItem(lit, false)); isFound = true; } else { popItem.Literal.SetValue(null); } } backjumpCount++; }