Сокращение для предикатов множественного выбора в clingo

Прямо сейчас у меня есть один предикат выбора, который определяет мое пространство поиска.

#const nRounds = 3.
#const nPlayers = 17.
#const nSeats = nRounds * nPlayers.
#const nRooms = 3.
#const nDecks = 6.

nSeats { seat(1..nPlayers, 1..nRooms, 1..nDecks) } nSeats.

Я хотел бы ограничить это пространство поиска, так как начинаю сталкиваться с проблемами производительности. В моей настройке каждый игрок может появляться только в 4 предикатах места, поэтому я хотел бы что-то вроде:

#for i in 1..nPlayers
nRounds { seat(i, 1..nRooms, 1..nDecks) } nRounds.
#endfor

который в основном превратился бы во что-то вроде этого внутри:

nRounds { seat(1, 1..nRooms, 1..nDecks) } nRounds.
nRounds { seat(2, 1..nRooms, 1..nDecks) } nRounds.
nRounds { seat(3, 1..nRooms, 1..nDecks) } nRounds.
...

Я мог бы, конечно, написать это сам, т. е. использовать другой язык для создания этих строк, но я не понимаю, почему этого не существует в clingo.

Причина, по которой я ищу способ сделать это, в первую очередь заключается в том, что я ожидаю, что (nRooms*nDecks choose nRounds) * nPlayers будет намного меньше, чем (nRooms*nDecks*nPlayers) choose nRounds*nPlayers, что, в свою очередь, намного лучше, чем {seat(P, R, D)} с его 2^(nRooms*nDecks*nPlayers), с которого я начал.

Даже с ограничениями в моем коде, которые ограничивают фактические возможные наборы, которые я могу получить, чтобы все три из этих представлений были эквивалентны, все же есть преимущества в производительности, которые можно получить от такого ручного сокращения пространства поиска, верно?


person rudolfovic    schedule 12.05.2021    source источник


Ответы (1)


Цикл for, который вы ищете, представляет собой прямое правило:

nRounds { seat(S, 1..nRooms, 1..nDecks) } nRounds :- S = 1..nPlayers.

Проверьте разницу с вашим кодом с помощью clingo --text

Я бы также посоветовал вам разделить предикат seat(P,R,D) на несколько меньших (в зависимости от вашей проблемы. Например, каждому игроку назначается комната p2r(P,R), а каждой комнате назначается колода r2d(R,D). Таким образом, вы сохраняете много ненужных комбинаций в своих ограничениях. позже.Конечно, мой предикат two может не иметь смысла для вашей проблемы, но я уверен, что вы найдете комбинацию, чтобы разделить предикат места.

person Max Ostrowski    schedule 12.05.2021
comment
Великолепно, так что я думаю, вы можете сделать то же самое с наборами, например. S = (a;b;c)? Есть несколько колод, и каждая играется в нескольких комнатах, поэтому я не думаю, что это можно упростить еще больше. Подумайте о вечере викторины - колоды могут быть биология, химия, физика, каждая из которых играется параллельно в нескольких комнатах разными людьми. Я мог бы разделить seat(P,R,D) на seat(P, ID) и round(ID, R, D), но я не думаю, что это будет иметь какое-либо значение, поскольку в конечном итоге |ID| будет равно |R|*|D|, верно? - person rudolfovic; 13.05.2021
comment
Конечно, просто попробуйте и протестируйте с --text. round(1..5). player(1..5). deck(1..5). room(1..5). %Assign every player every round exactly one room 1{where(P,R,X) : room(X)} 1 :- player(P), round(R). %Assign every room every round exactly one deck 1{what(X,R,D) : deck(D)}1:- room(X), round(R). - person Max Ostrowski; 14.05.2021
comment
Есть ли разница между {what(X,R,D): deck(D)} и {what(X,R,1..5)}? - person rudolfovic; 14.05.2021
comment
Нет, просто более многоразовый и читабельный. И конечно же колода может иметь названия не только цифр. - person Max Ostrowski; 14.05.2021