Example #1
0
        // 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);
        }
Example #2
0
        // 作った 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");
                }
            }
        }
Example #3
0
        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);
        }
Example #5
0
        // 変数が 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);
        }
Example #7
0
        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);
        }
Example #8
0
        // 値域の中のどれか一つは取れるという制約を出力
        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);
        }