2013-12-09 3 views
3

swi-prolog에서 이진 스도쿠 해결사를 작성하려고했습니다. (이진 스도쿠가 설명되어 있습니다 here)prolog 스도쿠 솔버의 글로벌 스택이 부족합니다

문제는 현재 글로벌 스택이 부족하다는 것입니다. 나는 그것보다 더 충분해야 2 기가 바이트주고있다. 결함이있는 알고리즘을 사용하고 있습니까? 저기 작은 퍼즐과 함께 글로벌 스택 오류의 부족으로 실행 피하기 위해 더 잘할 수있는 일이 있습니까?

조금 더 많은 정보 : 첫 번째 제한 조건을 적용한 4x4 퍼즐에 이미 6^4 가지 가능성이 있습니다. 당신이이 문제를 조회 할 수 있습니다 : 여기

problems(2,Field),binary_sudoku(Field). 

코드 : 코드에 문제가 몇 가지가 있습니다

:-use_module(library(clpfd)). 

valid_row(Row) :- 
    Row ins 0..1, 
    length(Row,L), 
    sum(Row,#=,L/2). 

matrixNth1(Matr,X,Y,El) :- 
    nth1(Y,Matr,CurRow), 
    nth1(X,CurRow,El). 

all_diff([]). 
all_diff([X|Y]) :- 
    maplist(dif(X),Y), 
    all_diff(Y). 


valid(_,1,1). 
valid(Rows,1,Y) :- 
    length(Rows,Y). 
valid(Rows,X,1) :- 
    length(Rows,X). 
valid(Rows,X,X) :- 
    length(Rows,X). 

valid(Rows,X,Y) :- 
    matrixNth1(Rows,X,Y,0). 
valid(Rows,X,Y):- 
    AboveY is Y-1, 
    matrixNth1(Rows,X,AboveY,0). 
valid(Rows,X,Y):- 
    BelowY is Y+1, 
    matrixNth1(Rows,X,BelowY,0). 
valid(Rows,X,Y):- 
    LeftX is X-1, 
    matrixNth1(Rows,LeftX,Y,0). 
valid(Rows,X,Y):- 
    RightX is X+1, 
    matrixNth1(Rows,RightX,Y,0). 

binary_sudoku(Rows) :- 
    length(Rows,Height), 
    transpose(Rows,Cols), 
    length(Cols,Height), 
    maplist(valid_row,Rows), 
    foreach(between(1,Height,X),foreach(between(1,Height,Y),valid(Rows,X,Y))), 
    all_diff(Rows),all_diff(Cols). 


problems(1,[[_,_],[_,_]]). 

problems(2,[[_,_,_,_],[_,_,_,_],[_,_,_,_],[_,_,_,_]]). 
+0

어떻게 당신이 솔루션에 대한 쿼리하는? 이미 사용 가능한'all_different/1' 또는'all_distinct/1'을 사용하는 대신 자신의'all_diff'를 정의하는 이유는 무엇입니까? 왜 "모든 다른"제약 조건을 더 일찍 설정하지 않습니까? –

+0

나는 이것이 내가 프롤로그에서 만든 첫 번째 것이라고 덧붙여 야했다. C에서 오는 clunky/magical 한 것 같다. .... 리스트를 원할 때 정수가 다른 것을 제약하기 때문에 all_distinct가 작동하지 않았다. 정수의 다른 것입니다. 상관없이 all_diff는 문제가 아니며 비 고유 행/열이있는 솔루션은 거의 없습니다. 그것은 내가 말할 수있는 한 내 이중 foreach 루프에 문제가 있습니다. – camel

+0

2x2 보드의 솔루션을 얻으시겠습니까? 그것을 얻으려면 어떻게 질문합니까? –

답변

3

. 정말로 Prolog/clpfd 초심자라면 좀 더 쉽게 시작하는 것이 좋습니다.

CLP 프로그램의 아이디어는 먼저 제약 조건 (결정적 임)을 설정 한 다음 솔루션 (비 결정적)을 검색하는 것입니다. 코드에서 valid_row/1과 all_diff/1은 제약 조건으로 간주 될 수 있지만 valid/3은 비 결정적이며 많은 선택을합니다.

첫 번째 변경 사항은 유효한/3로 통화를 맨 끝으로 이동하는 것입니다.

그러면 유효한 모든 변수 할당을 체계적으로 열거하도록 valid/3을 변경해야합니다. 현재 코드 및 3 × 3 행렬

foreach(between(1,Height,X),foreach(between(1,Height,Y),valid(Rows,X,Y))) 

가 생성하는 처음 몇 솔루션을 통해 그들은 여전히 ​​변수를 포함하기 때문에, 나쁜

[[A, 0, C], [0, 0, 0], [G, 0, I]] 
[[A, 0, C], [0, 0, 0], [G, 0, 0]] 
[[A, 0, C], [0, 0, 0], [G, 0, I]] 
[[A, 0, C], [0, 0, 0], [G, 0, I]] 
[[A, 0, 0], [0, 0, F], [G, 0, I]] 
... 

을하고, 그들은 심지어 상호 배타적이지 않다. 둘 다 동일한 숙제를 반복해서 방문하는 것을 의미합니다. 성공할 때마다 모든 변수가 0/1로 설정되고 모든 솔루션이 달라 지도록 다시 작성하십시오. 그런 다음 검색 공간을 한 번만 탐색해야하며 합리적인 시간에 솔루션을 찾을 수있는 기회를 가질 수 있습니다.

+0

그래서 프롤로그에서 변수 사이의 관계 대신 개별 솔루션을 반환해야합니까? – camel

+0

내가 알 수있는 한, 유효/3은 변수들 사이에 어떠한 관계도 설정하지 않습니다. 이것은 여러 변수를 인스턴스화하는 몇 가지 대안 절로 구성됩니다. 오히려해야 할 일은 가능한 모든 값에 대해 단일 변수를 인스턴스화하는 것입니다. – jschimpf

5

여기 ECLiPSe의 컴팩트 솔루션 (제약 조건 및 모델링 확장이있는 Prolog, http://eclipseclp.org)입니다. 행/열 당 0/1 수, 3 -1 조건이없는 경우 시퀀스/4 제약 조건 및 행 간의 차이를 적용하는 lex_ne/2 수에 대한 합계 제약 조건을 사용합니다. 솔루션 검색은 끝에 레이블링/1 호출에 의해 수행됩니다. 또한 매트릭스 표기법이 사용되며 이는 이러한 설정의 목록보다 편리합니다.

:- lib(gfd). 

solve(Name, Mat) :- 
    problem(Name, Mat), 
    dim(Mat, [N,N]), 
    Mat #:: 0..1, 
    N #= 2*K, 
    (for(I,1,N), param(Mat,K,N) do 
     sum(Mat[I,1..N]) #= K, 
     sum(Mat[1..N,I]) #= K, 
     sequence(1, 2, 3, Mat[I,1..N]), 
     sequence(1, 2, 3, Mat[1..N,I]), 
     (for(J,I+1,N), param(Mat,I,N) do 
      lex_ne(Mat[I,1..N], Mat[J,1..N]), 
      lex_ne(Mat[1..N,I], Mat[1..N,J]) 
     ) 
    ), 
    labeling(Mat). 

problem(2, [](
    [](_,1,0,_,_,_,_,0,_,_,0,_), 
    [](_,1,1,_,_,1,_,_,_,_,_,_), 
    [](_,_,_,_,_,_,_,_,1,_,_,0), 
    [](_,_,0,0,_,_,_,_,_,_,_,0), 
    [](_,_,_,_,_,_,1,1,_,0,_,_), 
    [](_,1,_,0,_,1,1,_,_,_,1,_), 
    [](_,_,_,_,_,_,_,_,1,_,_,_), 
    [](1,_,_,1,_,_,_,_,_,_,0,_), 
    [](_,1,_,_,_,_,_,_,0,_,_,_), 
    [](_,_,_,_,_,_,_,0,_,_,_,_), 
    [](1,_,_,_,_,_,_,_,_,_,_,1), 
    [](_,1,_,1,_,_,_,_,_,0,0,_))). 

이 신속하게 (독특한) 솔루션을 제공합니다 :

?- solve(2, M). 
M = []([](1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0), 
     [](0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1), 
     [](1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0), 
     [](1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0), 
     [](0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1), 
     [](0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0), 
     [](1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1), 
     [](1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1), 
     [](0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0), 
     [](0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0), 
     [](1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1), 
     [](0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1)) 
Yes (0.03s cpu, solution 1, maybe more)