在 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,Deck) } :- what(Player,Deck),where(Player,Room),who(Player,Deck).

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

%:- room(R1),deck(D),room(R2),X = #sum { P: seat(P,R1,D) },Y = #sum { P: seat(P,R2,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,D) :- points(P,X),X = #max { Y : points(_,Y) }.
% Compute each player's rank based on each round:
% rank(P,R) :- points(P,winner(Winner,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,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,seat(Player2,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 名玩家(由于游戏规则,而不是空间)。
  • 每个 Deck 最多播放一次,并同时在多个房间播放 - 所以从某种意义上说,Deck 是“Round”的同义词。
  • 每位玩家最多只能玩同一副牌。
  • 每位玩家在夜间只能玩 N 次(N 几乎是固定的,它是 4)。
  • 所以如果在晚上玩 9 副套牌(即如果有很多玩家 现在),每个人将播放这 9 个中的 4 个。
  • 因此,没有必要让每个玩家都参加每个“套牌/回合”。事实上,每副套牌都有一个作者,通常是其中一个玩家
  • 当然,作者不能打自己的套牌,所以他们必须在那轮比赛中待在外面。此外,对于每一副牌/轮, 必须有人阅读每个房间的问题,所以如果 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 副套牌/轮。

附言你有两个回合的概念 - 一个是个人层面,每个人都有 4 个可以玩,另一个是联盟级别,有一定数量的套牌>4,每个套牌在在场的每个人眼中都被认为是“一轮”。据我了解,这是关于设置的最令人困惑的一点,我在开始时没有很好地说明。

解决方法

我已经用你的新规范重写了编码,没有进行太多优化来解决问题。

备注: 我认为“阅读问题”的人是作家? 我保证每个房间有 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,D)}.                                                                  

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

plays(P,D) :- plays(P,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 轮,我们有 20 个玩家,这是 80 个单独的游戏。考虑到至少 3 个玩家必须在一个房间,我们有 4 个房间和 7 个甲板,这是 3 * 4 * 7 = 84,我们至少需要玩 84 场个人游戏)。你也可以计算我认为的甲板数量。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...