// this == var が成立するような expression を返す // (this == 1 && var == 1) || (this == 2 && var == 2) || ... public IExpression EqualCondition(VariableInteger var) { Debug.Assert(var.lowerbound == lowerbound); Debug.Assert(var.variables.Count == variables.Count); var ret = new ExpressionOr(); for (int i = 0; i < variables.Count; i++) { var item = new ExpressionAnd(); for (int j = 0; j < variables.Count; j++) { if (i == j) { item.children.Add(new ExpressionInteger(variables[j], true)); item.children.Add(new ExpressionInteger(var.variables[j], true)); } else { item.children.Add(new ExpressionInteger(variables[j], false)); item.children.Add(new ExpressionInteger(var.variables[j], false)); } } ret.children.Add(item); } return(ret); }
// 作った CNF を出力する static void Dump(Int32 varCount, ExpressionAnd CNF) { var cnfSize = CNF.children.Count; Console.Error.WriteLine($"p cnf {varCount} {cnfSize}"); foreach (var child in CNF.children) { if (typeof(ExpressionInteger) == child.GetType()) { var itemInt = (ExpressionInteger)child; var val = itemInt.positive ? itemInt.id : -itemInt.id; Console.Error.WriteLine($"{val} 0"); } else if (typeof(ExpressionOr) == child.GetType()) { foreach (var item in child.children) { var itemInt = (ExpressionInteger)item; var val = itemInt.positive ? itemInt.id : -itemInt.id; Console.Error.Write($"{val} "); } Console.Error.WriteLine(0); } else { throw new Exception("unexpected type"); } } }
public override IExpression Negate() { var expr = new ExpressionAnd(); foreach (var child in children) { expr.children.Add(child.Negate()); } return(expr); }
// variables の中の変数は全て異なる private IExpression DifferentAll(List <VariableInteger> variables) { var expr = new ExpressionAnd(); foreach (var v1 in variables) { foreach (var v2 in variables) { if (v1.id != v2.id) { expr.children.Add(v1.NotEqualCondition(v2)); } } } return(expr); }
// 変数が var という値を取る制約 public IExpression EqualCondition(Int32 var) { Debug.Assert(lowerbound <= var && var < lowerbound + variables.Count); var expr = new ExpressionAnd(); for (int i = 0; i < variables.Count; i++) { if (lowerbound + i == var) { expr.children.Add(new ExpressionInteger(variables[i], true)); } else { expr.children.Add(new ExpressionInteger(variables[i], false)); } } return(expr); }
// expr を簡約した結果を返す // 新規変数を追加する時に生じた制約は、 newExpr に入れる public IExpression TseitinTranslate(IExpression expr, ExpressionAnd newExpr) { var ret = expr.Empty(); foreach (var child in expr.children) { // 簡約の必要がない if (child.GetType() == typeof(ExpressionInteger)) { ret.children.Add(child); } else { // 再帰的に簡約 var childExpr = TseitinTranslate(child, newExpr); // childExpr を newId の変数で置き換え var newId = generator.GenerateId(); ret.children.Add(new ExpressionInteger(newId, true)); // childExpr == newId の制約 var newChildExpr = new ExpressionInteger(newId, false); if (childExpr.GetType() == typeof(ExpressionAnd)) { foreach (var subexpr in childExpr.children) { var newSubExpr = new ExpressionOr(); newSubExpr.children.Add(newChildExpr.Clone()); newSubExpr.children.Add(subexpr); newExpr.children.Add(newSubExpr); } } else // childExpr.GetType() == typeof (ExpressionOr) { childExpr.children.Add(newChildExpr); newExpr.children.Add(childExpr); } } } return(ret); }
public override IExpression Flatten() { var ret = new ExpressionAnd(); foreach (var child in children) { var flatten = child.Flatten(); if (GetType() == child.GetType()) { foreach (var child2 in flatten.children) { ret.children.Add(child2); } } else { ret.children.Add(flatten); } } return(ret); }
// 値域の中のどれか一つは取れるという制約を出力 public IExpression AssignAny() { var ret = new ExpressionOr(); for (int i = 0; i < variables.Count; i++) { var item = new ExpressionAnd(); // 下から i 番目の値が採用されるような割当て for (int j = 0; j < variables.Count; j++) { if (i == j) { item.children.Add(new ExpressionInteger(variables[j], true)); } else { item.children.Add(new ExpressionInteger(variables[j], false)); } } ret.children.Add(item); } return(ret); }
public ExpressionAnd encode(List <List <Int32> > board) { Debug.Assert(board.Count == size); foreach (var line in board) { Debug.Assert(line.Count == size); } // 最終的に生成される CNF var ret = new ExpressionAnd(); // 最初から埋まってる数字の初期配置 for (int col = 0; col < size; col++) { for (int row = 0; row < size; row++) { if (board[col][row] > 0) { ret.children.Add(vars[col][row].EqualCondition(board[col][row])); } } } // 1〜9 のどれかの値は割り当てられる for (int col = 0; col < size; col++) { for (int row = 0; row < size; row++) { ret.children.Add(vars[col][row].AssignAny()); } } // 縦が全て異なる値 for (int col = 0; col < size; col++) { var lst = new List <VariableInteger> (); for (int row = 0; row < size; row++) { lst.Add(vars[col][row]); } ret.children.Add(DifferentAll(lst)); } // 横が全て異なる値 for (int row = 0; row < size; row++) { var lst = new List <VariableInteger> (); for (int col = 0; col < size; col++) { lst.Add(vars[col][row]); } ret.children.Add(DifferentAll(lst)); } Int32 subsize = (Int32)Math.Round(Math.Sqrt(size)); // 各 grid 内が全て異なる値 for (int gcol = 0; gcol < subsize; gcol++) { for (int grow = 0; grow < subsize; grow++) { var lst = new List <VariableInteger> (); for (int lcol = 0; lcol < subsize; lcol++) { for (int lrow = 0; lrow < subsize; lrow++) { var col = gcol * subsize + lcol; var row = grow * subsize + lrow; lst.Add(vars[col][row]); } } ret.children.Add(DifferentAll(lst)); } } var ret2 = new ExpressionAnd(); // 一番浅い部分は省略する必要がないので、いらない foreach (var child in ret.Flatten().children) { if (child.GetType() == typeof(ExpressionInteger)) { ret2.children.Add(child); } else // if ExpressionOr { var simpleChild = TseitinTranslate(child, ret2); ret2.children.Add(simpleChild); } } return(ret2); }