Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List &引用;“生成数字”;令人费解的事_List_Constraint Programming_Logic Programming_Picat - Fatal编程技术网

List &引用;“生成数字”;令人费解的事

List &引用;“生成数字”;令人费解的事,list,constraint-programming,logic-programming,picat,List,Constraint Programming,Logic Programming,Picat,我遇到了以下难题,无法在Picat中制定解决方案: 您将生成5位数字,其中每个数字位于1..5中,并且与其他数字不同,但有一个限制,即一个数字中使用的任何三个相邻数字都不能用于另一个数字。 根据这个规则可以得到多少不同的数字 例如,如果我们生成了编号12345,则其他编号不能包含123、345或456,因此链中禁止以下形式的所有编号: 123AB, A123B, AB123, 234AB, A234B, AB234, 345AB, A345B, AB345, 在建立数字列表时,我对如何存储这些

我遇到了以下难题,无法在Picat中制定解决方案:

您将生成5位数字,其中每个数字位于
1..5
中,并且与其他数字不同,但有一个限制,即一个数字中使用的任何三个相邻数字都不能用于另一个数字。 根据这个规则可以得到多少不同的数字

例如,如果我们生成了编号
12345
,则其他编号不能包含
123
345
456
,因此链中禁止以下形式的所有编号:

123AB, A123B, AB123,
234AB, A234B, AB234,
345AB, A345B, AB345,
在建立数字列表时,我对如何存储这些“禁止”子列表以及如何对照它们检查每个数字感到非常困惑

我的尝试:

我想我已经为给定的链状态生成了有效的“候选者”,但是我不知道如何生成这样的链

import cp.
import util.

valid(Ls, Cd) ?=>
    % verify that the head of the chain is correct?
    % so the chain consists of permutations of 12345
    foreach (L in Ls)
        len(L) = 5,
        permutation(L, [1,2,3,4,5])
    end,
    
    % generate the candidate
    Cd = new_list(5),
    permutation(Cd, [1,2,3,4,5]),
    
    % check the candidate against the head of the chain
    foreach (L in Ls)
        not sublist([L[1],L[2],L[3]], Cd),
        not sublist([L[2],L[3],L[4]], Cd),
        not sublist([L[3],L[4],L[5]], Cd)
    end,

    solve(Ls),
    printf("Cd: %w\n", Cd),
    fail,
    nl.

% so that 3 element sublists of 12345 are 123,234 and 345.
sublist(X, S) =>
  append(_, T , S),
  append(X, _ , T),
  X.len #>= 0.

% seems to work, the candidates don't have the banned triplets as sublists.
% so in this case the banned triplets would be
% 123,234,345,543,432,321
go => valid([[1,2,3,4,5], [5,4,3,2,1]], _).

main => go.
评论:情况并非对称,这确实非常有趣。如果我们分析状态:

[12345,12435,12534,13245,13425,13524,14235,
14325,14523,21543,24153,25413,35421,43152]
我们看到,有效/可以附加到此链的三个候选项是:

Cd1: [5,3,2,1,4]
Cd2: [4,5,3,1,2]
Cd3: [4,5,3,2,1]
显然,如果我们选择
Cd3
,因为它同时包含
453
532
,它不允许我们在它之后选择任何候选项,因此链在
N=15
处结束

如果我们选择
Cd1
,它将排除
Cd3
,但仍保留
Cd2
,因此链继续到
N=16

类似地,如果我们选择
Cd2
,它会排除
Cd3
,但仍然保留
Cd1
,因此同样可以选择
N=16


因此,一般来说,有些候选对象包含(并因此排除)其他候选对象,而链的长度取决于我们是否选择这些候选对象。

这是Picat模型,模型位于更新4更新5更新6

更新6:如果不是因为错误的问题假设而从一开始就误入歧途,这可能是我编写的约束模型。。。这是一种更直接的方法(从约束程序员的角度来看),并且不使用
置换/1

它比更新5稍慢(使用sat解算器的速度为3.7s,而更新4的速度为3.3s)。但是,在该模型上,cp解算器的速度要慢得多。 在上面引用的Picat程序中,它的型号是go3/0。(最快的型号是
go/0

方法:

  • 创建具有域1..5的20 x 5矩阵
  • 对于每一行,确保它是不同的数字
  • 在循环中确保没有常见的三胞胎
模型:

go3 ?=>
  nolog,
  N = 5,
  M = 20,
  X = new_array(M,N),
  X :: 1..N,

  % symmetry breaking
  X[1,1] #= 1,X[1,2] #= 2,X[1,3] #= 3,X[1,4] #= 4,X[1,5] #= 5,
  foreach(I in 1..M)
    all_distinct([X[I,K] : K in 1..N]),
    foreach(J in 1..I-1)
      foreach(A in 0..2)
        foreach(B in 0..2)
          sum([X[I,K+A] #= X[J,K+B] : K in 1..3]) #< 3
        end
     end
   end
 end,

 solve($[ff,split],X),
 foreach(P in X)
   println(P.to_list)
 end,
 println(numbers=[[I.to_string : I in  T].join('').to_int : T in X]),  
 nl.
 go3 => true.
import sat, util.

go3 ?=>
   nolog,
   N = 5,
   Ps = permutations(1..N),
   PLen = Ps.len,
   % Find the triplets
   TripletsMap = new_map(),
   foreach(P in Ps)
     tri(P,Tri),
     foreach(T in Tri) TripletsMap.put(T,1) end
   end,
   % Convert to numbers (123..543)
   Triplets = [T[1]*100+T[2]*10+T[3] : T in keys(TripletsMap)].sort,

   % length of sequence
   member(M,20..20),
   println(m=M),

   % Indices of the selected permutation
   X = new_list(M),
   X :: 1..PLen,

   % The triplets
   Z = new_list(M*3),
   Z :: Triplets,

   % Y contains the "shortcuts" to the permutations
   Y = new_array(M,5),
   Y :: 1..N,

   all_distinct(X),
   all_distinct(Z),

   X[1] #= 1, % symmetry breaking

   % Fill Y
   foreach(I in 1..M)
      element(I,X,II),
      foreach(K in 1..5)
        matrix_element(Ps,II,K,Y[I,K])
      end
   end,

   % Convert triplet list in Y <-> triplet number in Z
   C = 1,
   foreach(I in 1..M)
      foreach(J in 1..3)
         to_num([Y[I,J+K] : K in 0..2],10,Z[C]), 
         C := C+1
      end
   end,

   Vars = Z ++ X ++ Y.vars,
   solve($[constr,updown,split],Vars) % split (SAT)

   PsX = [Ps[I] : I in X],
   println(numbers=[[I.to_string : I in  Ps[T]].join('').to_int : T in X]),  
     nl.
go3 => true.


tri(P,Tri) :- Tri=[P[K..K+2] : K in 1..3].

% converts a number Num to/from a list of integer 
% List given a base Base
to_num(List, Base, Num) =>
   Len = length(List),
   Num #= sum([List[I]*Base**(Len-I) : I in 1..Len]).
更新5这里有一个更快的方法:大约3.3秒找到第一个解决方案,而更新4中的方法为1分钟

这里的方法是:

  • 预处理步骤:从120个排列(
    Ps
    ),构建一个0/1的120 x 120矩阵
    a
    ,其中
    a[P1,P2]=1
    意味着
    Ps[P1]
    Ps[P2]
    是兼容的,即它们没有公共三元组
  • 模型:创建一个长度为120的0/1列表
    X
    ,其中
    X[I]=1
    意味着排列
    Ps[I]
    应该在序列中(或者更确切地说是“设置”,因为排列的顺序没有区别)
  • 在foreach循环中,
    X[I]*X[J]#=1#=>A[I,J]
    是一种“奇怪”的说法,如果
    A[I,J]
    X[J]
    都应该在序列中
cp解算器大约需要3.3秒才能找到第一个长度为20的解。该模型的sat解算器速度较慢:4.8s(因此它仍然比更新4版本快得多)

以下是完整的模型:

go ?=>
  N = 5,
  Ps = permutations(1..N),
  PsLen = Ps.len,
  % Compatibility matrix: 
  % A[P1,P2] = 1 if they don't have any common triple
  A = new_array(PsLen,PsLen),
  bind_vars(A,0),
  foreach(P1 in 1..PsLen)
    A[P1,P1] := 1,  
    foreach(P2 in 1..PsLen, P1 < P2)
      if check_perms(Ps[P1],Ps[P2]) then
        A[P1,P2] := 1,
        A[P2,P1] := 1
      end
    end 
 end,

 M = 20, % length 20 sequence
 println(m=M),

 % List of 0/1: 
 % 1 means that it should be in the sequence
 X = new_list(PsLen),
 X :: 0..1,
 sum(X) #= M, % We want M 1s

 X[1] #= 1, % symmetry breaking
 foreach(I in 1..PsLen)
   foreach(J in 1..I-1)
     X[I]*X[J] #= 1 #=> A[I,J]
   end
 end,

 solve($[degree,updown],X),

 println(x=X),
 Perms = [Ps[I] : I in 1..PsLen, X[I]==1],
 foreach(P in Perms)
   println(P)
 end,
 println(numbers=[[I.to_string : I in  T].join('').to_int : T in Perms]),    
 % println("Checking:"),
 % foreach(I in 1..Perms.len, J in 1..I-1)
 %    if not check_perms(Perms[I],Perms[J]) then
 %       println("ERROR!"=Perms[I]=Perms[J])
 %    end
 % end,
 nl,
 % fail,

 nl.
go4 => true.

% list version
check2(Forbidden,Tri) =>
  foreach(PP in Tri)
    not membchk(PP,Forbidden)
 end.

check_perms(Perm1,Perm2) =>
  tri(Perm1,Tri1),
  tri(Perm2,Tri2),     
  foreach(PP in Tri2)
    not membchk(PP,Tri1)
  end,
  foreach(PP in Tri1)
    not membchk(PP,Tri2)
  end.

tri(P,Tri) :- Tri=[P[K..K+2] : K in 1..3].
更新4如评论中所述,这里有一个约束模型,它可以找到长度为20的序列

根据以下推理,seq为20是最佳的:在1..5的120个排列的集合中,有60个可能的三联体。每个数字由3个唯一的三元组组成。因此,在这样的序列中不能有超过60/3=20个数字

这是一个20个数字的序列:

[12345,32451,43125,15423,23541,41532,52134,
 24135,14352,31524,54321,25314,42513,51243,
 34215,53412,45231,35142,21453,13254]
这个使用sat解算器的模型需要大约1min25来开始这个序列。它比以前版本中使用回溯的列表处理的“简单”使用要详细一些,这就是这些方法中获得最大长度序列的问题

一些评论:

  • 矩阵_元素/4
    用于连接
    Y
    矩阵中的三元组和
    Z
    中的数字
  • 三元组表示为数字123..543(在
    Z
    中),因此我们可以确保它们是不同的
  • 与往常一样,Picat的
    cp
    模块在较简单的实例(例如,长度高达16)上速度更快,但对于较大的实例(>16),则
    sat
    往往更好
模型:

go3 ?=>
  nolog,
  N = 5,
  M = 20,
  X = new_array(M,N),
  X :: 1..N,

  % symmetry breaking
  X[1,1] #= 1,X[1,2] #= 2,X[1,3] #= 3,X[1,4] #= 4,X[1,5] #= 5,
  foreach(I in 1..M)
    all_distinct([X[I,K] : K in 1..N]),
    foreach(J in 1..I-1)
      foreach(A in 0..2)
        foreach(B in 0..2)
          sum([X[I,K+A] #= X[J,K+B] : K in 1..3]) #< 3
        end
     end
   end
 end,

 solve($[ff,split],X),
 foreach(P in X)
   println(P.to_list)
 end,
 println(numbers=[[I.to_string : I in  T].join('').to_int : T in X]),  
 nl.
 go3 => true.
import sat, util.

go3 ?=>
   nolog,
   N = 5,
   Ps = permutations(1..N),
   PLen = Ps.len,
   % Find the triplets
   TripletsMap = new_map(),
   foreach(P in Ps)
     tri(P,Tri),
     foreach(T in Tri) TripletsMap.put(T,1) end
   end,
   % Convert to numbers (123..543)
   Triplets = [T[1]*100+T[2]*10+T[3] : T in keys(TripletsMap)].sort,

   % length of sequence
   member(M,20..20),
   println(m=M),

   % Indices of the selected permutation
   X = new_list(M),
   X :: 1..PLen,

   % The triplets
   Z = new_list(M*3),
   Z :: Triplets,

   % Y contains the "shortcuts" to the permutations
   Y = new_array(M,5),
   Y :: 1..N,

   all_distinct(X),
   all_distinct(Z),

   X[1] #= 1, % symmetry breaking

   % Fill Y
   foreach(I in 1..M)
      element(I,X,II),
      foreach(K in 1..5)
        matrix_element(Ps,II,K,Y[I,K])
      end
   end,

   % Convert triplet list in Y <-> triplet number in Z
   C = 1,
   foreach(I in 1..M)
      foreach(J in 1..3)
         to_num([Y[I,J+K] : K in 0..2],10,Z[C]), 
         C := C+1
      end
   end,

   Vars = Z ++ X ++ Y.vars,
   solve($[constr,updown,split],Vars) % split (SAT)

   PsX = [Ps[I] : I in X],
   println(numbers=[[I.to_string : I in  Ps[T]].join('').to_int : T in X]),  
     nl.
go3 => true.


tri(P,Tri) :- Tri=[P[K..K+2] : K in 1..3].

% converts a number Num to/from a list of integer 
% List given a base Base
to_num(List, Base, Num) =>
   Len = length(List),
   Num #= sum([List[I]*Base**(Len-I) : I in 1..Len]).
第一个解决方案的长度为16:

  [12345,12435,12534,13245,13425,13524,14235,14325,
   14523,21543,24153,25413,35421,43152,45312,53214]
但是,下一个解决方案(通过回溯)的长度为15:

  [12345,12435,12534,13245,13425,13524,14235,14325,
   14523,21543,24153,25413,35421,43152,45321]
所以我仍然不确定16是否是最大长度

Update2:在Update中的版本不是完全正确的(事实上它是完全错误的),因为我忘了在循环中将三元组添加到
禁止的
添加禁止的\u三元组(禁止的,三元组)
。程序更新如下

具有12345的第一个解决方案的起始编号为:

   [12345,23145,13245,13425,34125,12435,24135,14235,
    14325,43152,42153,45213,45312,53214]
   len = 14
现在它变得有趣了,因为其他序列的长度(不同的起始数字)大约是12到17个数字。这与直觉相反,因为这些东西应该是对称的,不是吗

更新:由于我第一次错过了说明中的一个重要约束,这里有一个调整后的p
   [12345,23145,13245,13425,34125,12435,24135,14235,
    14325,43152,42153,45213,45312,53214]
   len = 14
go ?=>
  N = 5,
  Ps = permutations(1..N),
  select(P,Ps,Ps2),
  L = [P],
  tri(P,Triplets),
  Forbidden = new_map(), % keep forbidden triplets in a hash table
  add_forbidden_triplets(Forbidden, Triplets), % added in **Update2**
  Found = true,
  while(Found == true)
    if select(NextP,Ps2,Ps3), tri(NextP,PTri), check(Forbidden,PTri)    then
      L := L ++ [NextP],
      add_forbidden_triplets(Forbidden, PTri),
      P := NextP,
      Ps2 := Ps3
    else
      Found := false
    end
   end,
   println([[I.to_string : I in  C].join('').to_int : C in L]),  
   println(len=L.len),
   nl,
   % fail, % generate a new solution
   nl.
 go => true.

 %
 % Create triplets (Tri) from the permutation P
 %
 tri(P,Tri) :- Tri=[P[K..K+2] : K in 1..3].

 %
 % Check if Tri contain some forbidden triplet
 %
 check(Forbidden,Tri) =>
   foreach(PP in Tri)
     not Forbidden.has_key(PP)
   end.


 %
 % Add triplets to Forbidden map
 %  
 add_forbidden_triplets(Forbidden,Triplets) =>
   foreach(T in Triplets)
     Forbidden.put(T,1)
   end.
[12345,23145,13245,31245,32145,32415,32451,13425,
 1425,34125,34215,34251,31452,34152,12435,21435,
 24135,24315,24351,14235,42135,42315,42351,14325,
 41325,43125,43215,43251,14352,41352,43152,43512,
 43521,12453,21453,24153,24513,24531,14253,41253,
 42153,42513,42531,14523,41523,45213,45231,14532,
 41532,45132,45312,45321,21354,23154,23514,23541,
 13254,31254,32154,32514,32541,13524,31524,35124,
 35214,35241,13542,31542,35142,35412,35421,12534,
 21534,25134,25314,25341,52134,52314,15324,51324,
 53124,53214,53241,15342,51342,53142,53412,53421,
 12543,21543,25143,25413,25431,15243,51243,52143,
 52413,52431,15423,51423,54213,54231,15432,51432,
 54132,54312,54321]
 len = 107
import util. 

% Using foreach loop
go ?=>
  N = 5,
  Ps = permutations(1..N),
  select(P,Ps,Ps2), % pick the first number (i.e. 12345)
  L := [P],
  while(Ps2 != [])    
    tri(P,Forbidden),
    select(NextP,Ps2,Ps3),
    tri(NextP,PTri),
    check(Forbidden,PTri),
    L := L ++ [NextP],
    P := NextP,   
    Ps2 := Ps3
  end,
  println([[I.to_string : I in  C].join('').to_int : C in L]), % convert to number
  nl.
go => true.

% Using genx/2 ("Prolog style")
go3 ?=>
  Ps = permutations(1..5),
  PLen = Ps.len,
  println(plen=PLen),
  genx(Ps,L),
  println(len=L.len),
  nl.
go3 => true.


% Create triplets (Tri) from the permutation P
tri(P,Tri) :- Tri=[P[K..K+2] : K in 1..3].

 % Check if Tri contain some forbidden triplet
 check(Forbidden,Tri) =>
   foreach(PP in Tri)
     not membchk(PP,Forbidden)
   end.


 % This is the same principal logic as used in go/0 
 % but in "Prolog style"
 genx([],[]).
 genx([P],[P]).
 genx([P|Ps],[P|L]) :-
   tri(P,Forbidden),
   select(Next,Ps,Ps2), % pick a new available number
   tri(Next,Tri),
   check(Forbidden,Tri),
   genx([Next|Ps2],L).
[12345,23145,21345,23415,13245,23451,31245,32145,32415,
 13425,32451,31425,34125,34215,13452,34251,31452,34152,
 34512,12435,34521,21435,24135,24315,14235,24351,41235,
 42135,42315,14325,42351,41325,43125,43215,14352,43251,
 41352,43152,43512,12453,43521,21453,24153,24513,14253,
 24531,41253,42153,42513,14523,42531,41523,45123,45213,
 14532,45231,41532,45132,45312,12354,45321,21354,23154,
 23514,13254,23541,31254,32154,32514,13524,32541,31524,
 35124,35214,13542,35241,31542,35142,35412,12534,35421,
 21534,25134,25314,15234,25341,51234,52134,52314,15324,
 52341,51324,53124,53214,15342,53241,51342,53142,53412,
 12543,53421,21543,25143,25413,15243,25431,51243,52143,
 52413,15423,52431,51423,54123,54213,15432,54231,51432,
 54312,54132,54321]