Как преобразовать векторы в массивы в ECLiPSe (CLP)? (или Пролог)

Мне нужно решать головоломки судоку в формате вектора, содержащего 9 векторов (длиной по 9 каждый). Видя, что векторы представляют собой связанные списки в Прологе, я решил, что поиск будет быстрее, если я сначала преобразовал головоломки в формат 2D-массива.

Пример головоломки:

puzzle(P) :- P = 
[[_,_,8,7,_,_,_,_,6],
[4,_,_,_,_,9,_,_,_],
[_,_,_,5,4,6,9,_,_],

[_,_,_,_,_,3,_,5,_],
[_,_,3,_,_,7,6,_,_],
[_,_,_,_,_,_,_,8,9],

[_,7,_,4,_,2,_,_,5],
[8,_,_,9,_,5,_,2,3],
[2,_,9,3,_,8,7,6,_]].

Я использую ECLiPSe CLP для реализации решателя. Лучшее, что я придумал, - это написать такой домен:

domain(P):-
  dim(P,[9,9]),
  P[1..9,1..9] :: 1..9.

и конвертер для головоломки (параметр P - это заданная головоломка, а Sudoku - это новая определенная сетка с 2D-массивом). Но у меня возникли проблемы с привязкой значений из данной исходной головоломки к моему 2D-массиву.

convertVectorsToArray(Sudoku,P):-
  ( for(I,1,9),
      param(Sudoku,P)
    do
      ( for(J,1,9),
          param(Sudoku,P,I)
        do
          Sudoku[I,J] is P[I,J]
      )
  ).

До этого я пробовал использовать список_массивов (http://eclipseclp.org/doc/bips/kernel/termmanip/array_list-2.html), но я продолжал получать ошибки типа. Как я это делал раньше:

convertVectorsToArray(Sudoku,P):-
  ( for(I,1,9),
      param(Sudoku,P)
    do
      ( for(J,1,9),
          param(Sudoku,P,I)
        do
          A is Sudoku[I],
          array_list(A,P[I])
      )
  ).

Когда мой судоку наконец выводит пример головоломки P в следующем формате:

Sudoku = []([](_Var1, _Var2, 8, 7, ..., 6), [](4, ...), ...)

тогда я буду счастлив.

обновить

Я попробовал еще раз с array_list; он почти работает со следующим кодом:

convertVectorsToArray(Sudoku,P):-
  ( for(I,1,9),
      param(Sudoku,P)
    do
      X is Sudoku[I],
      Y is P[I],
      write(I),nl,
      write(X),nl,
      write(Y),nl,
      array_list(X, Y)
  ).

Записи нужны для того, чтобы увидеть, как выглядят векторы / массивы. По какой-то причине он останавливается на второй итерации (вместо 9 раз) и выводит остальную часть головоломки в виде вектора векторов. Правильно назначается только первый вектор.

update2

Хотя я уверен, что ответ jschimpf правильный, я также выяснил свою собственную реализацию:

convertVectorsToArray(Sudoku,[],_).
convertVectorsToArray(Sudoku,[Y|Rest],Count):-
  X is Sudoku[Count],
  array_list(X, Y),
  NewCount is Count + 1,
  convertVectorsToArray(Sudoku,Rest,NewCount).

Спасибо за добавленное объяснение того, почему это не сработало раньше!


person Babyburger    schedule 12.03.2016    source источник


Ответы (1)


Самое простое решение - полностью избежать преобразования, написав спецификацию головоломки непосредственно в виде двумерного массива. «Массив» ECLiPSe - это просто структура с функтором '[]'/N, поэтому вы можете написать:

puzzle(P) :- P = [](
    [](_,_,8,7,_,_,_,_,6),
    [](4,_,_,_,_,9,_,_,_),
    [](_,_,_,5,4,6,9,_,_),

    [](_,_,_,_,_,3,_,5,_),
    [](_,_,3,_,_,7,6,_,_),
    [](_,_,_,_,_,_,_,8,9),

    [](_,7,_,4,_,2,_,_,5),
    [](8,_,_,9,_,5,_,2,3),
    [](2,_,9,3,_,8,7,6,_)).

Затем вы можете использовать этот двумерный массив непосредственно в качестве контейнера для переменных вашего домена:

sudoku(P) :-
    puzzle(P),
    P[1..9,1..9] :: 1..9,
    ...

Однако, если вы хотите сохранить спецификацию головоломки со списком списков и преобразовать ее в формат массива массивов, вы можете использовать array_list/2. Но поскольку это работает только для одномерных массивов, вам необходимо индивидуально преобразовать уровни вложенности:

listoflists_to_matrix(Xss, Xzz) :-
    % list of lists to list of arrays
    ( foreach(Xs,Xss), foreach(Xz,Xzs) do
        array_list(Xz, Xs)
    ),
    % list of arrays to array of arrays
    array_list(Xzz, Xzs).

Что касается причины, по которой ваш собственный код не работал: это связано с обозначением нижнего индекса P[I]. Этот

  • требует, чтобы P был массивом (вы использовали его в списках)
  • работает только в тех контекстах, где ожидается арифметическое выражение, например правая часть is/2, в арифметических ограничениях и т. д.
person jschimpf    schedule 12.03.2016