Эффективное сокращение пространства поиска в clingo

Я изо всех сил пытаюсь масштабировать проблему ограничения (она не работает для больших значений и / или если я пытаюсь оптимизировать, а не просто искать какое-либо решение). Я предпринял некоторые шаги, чтобы сократить пространство поиска, основываясь на советах из некоторых предыдущих вопросов, но это все еще задерживается. Есть ли еще какие-нибудь методы, которые помогут мне оптимизировать эти вычисления?

%%% constants %%%
#const nRounds = 4.
#const nPlayers = 20.
#const nRooms = 4.
#const nDecks = 7.

player(1..nPlayers).
room(1..nRooms).
deck(1..nDecks).
writer(1,1;2,2;3,3;4,4).

% For reference - that's what I started with:
%nRounds { seat(Player, 1..nRooms, 1..nDecks) } nRounds :- player(Player).

% Now instead I'm using a few building blocks
% Each player shall only play nRounds decks
nRounds { what(Player, 1..nDecks) } nRounds :- player(Player).
% Each player shall only play in up to nRounds rooms.
1 { where(Player, 1..nRooms) } nRounds :- player(Player).
% For each deck, 3 or 4 players can play in each room.
3 { who(1..nPlayers, Room, Deck) } 4 :- room(Room), deck(Deck).
% Putting it all together, hopefully, this leads to fewer combinations than the original monolithic choice rule.
{ seat(Player, Room, Deck) } :- what(Player, Deck), where(Player, Room), who(Player, Room, Deck).

% A player can only play a deck in a single room.
:- seat(Player, Room1, Deck), seat(Player, Room2, Deck), Room1 != Room2.
% A player must play nRounds decks overall.
:- player(Player), #count { Room, Deck: seat(Player, Room, Deck) } != nRounds.
% Any deck in any room must be played by 3-4 players.
legal_player_count(3..4).
:- room(Room), deck(Deck),
  Players = #count { Player: seat(Player, Room, Deck) },
  Players > 0,
  not legal_player_count(Players).
% Writers cannot play their own decks.
:- writer(Player, Deck), seat(Player, _, Deck).
% At least one non-playing player per room.
:- deck(Deck),
  Playing = #count { Player, Room: seat(Player, Room, Deck) },
  Rooms = #count { Room: seat(_, Room, Deck) },
  nPlayers - Playing < Rooms.

%:- room(R1), deck(D), room(R2), X = #sum { P: seat(P, R1, D) }, Y = #sum { P: seat(P, R2, D) }, R1 > R2, X > Y.

#minimize { D: decks(D) }.

#show decks/1.
#show seat/3.
% #show common_games/3.

Когда или если это станет управляемым, я надеюсь добавить больше целей оптимизации, чтобы выбрать лучшие конфигурации по следующим направлениям:

% Input points(P, R, D, X) to report points.
% winner(P, R, D) :- points(P, R, D, X), X = #max { Y : points(_, R, D, Y) }.
% Compute each player's rank based on each round:
% rank(P, D, R) :- points(P, Room, D, X), winner(Winner, Room, D), D_ = D - 1,
%   rank(P, D_, R_),
%   R = some_combination_of(X, P=Winner, R_).
% latest_rank(P, R) :- D = #max { DD: rank(P, DD, _) }, rank(P, D, R).

% Total number of decks played throughout the night (for minimisation?)
decks(Decks) :- Decks = #count { Deck: seat(_, _, Deck) }.
% Total number of games played together by the same players (for minimisation)
% The total sum of this predicate is invariant
% Minimisation should took place by a superlinear value (e.g. square)
common_games(Player1, Player2, Games) :-
  player(Player1), player(Player2), Player1 != Player2,
  Games = #count { Room, Deck:
    seat(Player1, Room, Deck),
    seat(Player2, Room, Deck)
  }, Games > 0.

% For example:
% common_game_penalty(X) :- X = #sum { Y*Y, P1, P2 : common_games(P1, P2, Y) }.

% Another rank-based penalty needs to be added once the rank mechanics are there

% Then the 2 types of penalties need to be combined and / or passed to the optimiser

Обновление - описание проблемы

  • Игроки P собираются на ночь викторин. Для игры доступны колоды D и R.
  • В каждой комнате могут разместиться только 3 или 4 игрока (из-за правил игры, а не из-за места).
  • Каждая Колода разыгрывается не более одного раза и одновременно в нескольких комнатах, так что в некотором смысле Колода является синонимом Раунда.
  • Каждый игрок может играть одной и той же колодой не более одного раза.
  • Каждый игрок может сыграть только N раз за ночь (N практически фиксировано, а это 4).
  • Таким образом, если в течение ночи сыграно 9 колод (т.е.если присутствует много игроков), каждая сыграет 4 из этих 9.
  • Следовательно, нет необходимости, чтобы каждый игрок играл в каждой колоде / раунде. Фактически, для каждой колоды есть писатель, и это обычно один из присутствующих игроков.
  • Естественно, писатель не может разыграть свою колоду, поэтому в этом раунде он не участвует. Кроме того, для каждой колоды / раунда кто-то должен прочитать вопросы в каждой комнате, поэтому, если присутствует 16 игроков и есть 4 комнаты, все 16 игроков не смогут играть. Можно иметь 4 комнаты по 3 игрока в каждой (а оставшиеся 4 игрока зачитывают вопросы) или 3 комнаты по 4 игрока в каждой (3 игрока читают вопросы, а 1 наблюдает).

Надеюсь, это проясняет путаницу, если нет, я могу попытаться привести более подробные примеры, но в основном, скажем, если у вас 4 комнаты и 30 игроков:

  • Вы выбираете 16, кто будет играть, и еще 4, кто зачитает вопросы
  • Затем у вас есть 16 человек, которые сыграли своей 1/4 колодой / раундом, и 14 человек, которые все еще на 0/4.
  • Таким образом, вы можете либо позволить другим 14 людям играть (4,4,3,3 игрока на комнату), либо продолжить максимизировать полезность комнаты, чтобы после второго раунда все играли хотя бы один раз, а 2/30 игроков уже сыграли 2 / 4 игры.
  • Итак, вы продолжаете выбирать некоторое количество людей, пока все не сыграют ровно 4 колоды / раунда.

P.S. У вас есть 2 понятия раунда - одно на личном уровне, где у каждого есть 4 игры, а другое на уровне лиги, где имеется некоторое количество колод ›4, и каждая колода считается раундом в глазах всех присутствующих. Насколько я понял, это был самый запутанный момент в настройке, который я не очень хорошо прояснил вначале.


person rudolfovic    schedule 14.05.2021    source источник
comment
Было бы интересно, какие оптимизации вы до сих пор рассматривали. А как насчет нарушения симметрии? Не могли бы вы рассказать, какие проблемы возникают (в заземлении или решении)? Сколько основных правил вы создаете - какое из них плохо работает?   -  person tphilipp    schedule 14.05.2021
comment
1. Нет, соединив все вместе, вы создали такую ​​же сложность заземления, как и раньше (и даже хуже). 2. Я пытался закодировать вашу проблему, но потребовалось хорошее описание. - можно ли играть колодой более чем в одной комнате? -   -  person Max Ostrowski    schedule 15.05.2021


Ответы (1)


Я переписал кодировку в соответствии с вашей новой спецификацией без особых оптимизаций, чтобы решить проблему.

Примечания: Я предполагаю, что тот, кто читает вопросы, является писателем? Я заверил, что в каждой комнате есть по одному писателю, но не назвал его.

#const nPlayers = 20.                                                                                                  
#const nRooms = 4.                                                                                                     
#const nDecks = 6.                                                                                                     

player(1..nPlayers).                                                                                                   
room(1..nRooms).                                                                                                       
deck(1..nDecks).                                                                                                       

% player P plays in room R in round D                                                                                  
{plays(P,R,D)} :- deck(D), room(R), player(P).                                                                         

% a player may only play in a single room each round
:- player(P), deck(D), 1 < #sum {1,R : plays(P,R,D)}.                                                                  

% not more than 4 players per room                                                                                     
:- deck(D), room(R), 4 < #sum {1,P : plays(P,R,D)}.                                                                    
% not less than 3 players per room                                                                                     
:- deck(D), room(R), 3 > #sum {1,P : plays(P,R,D)}.                                                                    

plays(P,D) :- plays(P,R,D).                                                                                            
% at least one writer per room (we need at least one player not playing for each room, we do not care who does it)     
:- deck(D), nRooms > #sum {1,P : not plays(P,D), player(P)}.                                                           

% each player only plays 4 times during the night                                                                      
:- player(P), not 4 = #sum {1,D : plays(P,D)}.                                                                         

#show plays/3.                                                                                                         

%%% shortcut if too many decks are used, each player can only play 4 times but at least 3 players have to play in a room (currently there is no conecpt of an empty room)
:- 3*nRooms*nDecks > nPlayers*4. 

Обратите внимание, что я добавил последнее ограничение, так как ваша первоначальная конфигурация не была решаемой (каждый игрок должен сыграть ровно 4 раунда, а у нас двадцать игроков, это 80 отдельных игр. Учитывая, что в комнате должно быть как минимум 3 игрока, и у нас есть 4 комнаты и 7 колод (это 3 * 4 * 7 = 84, нам нужно будет сыграть не менее 84 индивидуальных игр). Думаю, вы могли бы также подсчитать количество колод.

person Max Ostrowski    schedule 15.05.2021
comment
Почему 3 #sum {1,P : where(R,P,Room)} 4, а не 3 #count {P: where(R,P,Room) }4? Также как несколько терминов (разделенных ;) работают в #count? - person rudolfovic; 16.05.2021
comment
Просто вопрос предпочтений, не важно. Для ; см. github.com/potassco/guide/releases см. 3.1.1 и 3.1. 12 - person Max Ostrowski; 17.05.2021
comment
Все, что я вижу, это руководство по Potassco версии 2.2.0 и руководство по Potassco версии 2.1.0, я не уверен, что именно вы имеете в виду. - person rudolfovic; 18.05.2021
comment
Обновил мое решение. @rudolfovic И я ссылался на руководство 2.2.0, но на главы 3.1.1 и 3.1.12;) - person Max Ostrowski; 18.05.2021
comment
Что касается: учитывая, что в комнате должно быть как минимум 3 игрока, а у нас есть 4 комнаты и 7 колод, это 3 * 4 * 7 = 84, нам нужно будет сыграть не менее 84 отдельных игр) - комнаты - это ресурс. Их может быть сотня, но если появятся только 5 игроков, они будут просто играть 5 колодами в одной комнате (4 игрока одновременно), так что в итоге все они сыграют ровно 4/5 колод. Колоды также являются просто ресурсом - разыгрывать все доступные колоды не обязательно. - person rudolfovic; 19.05.2021