Created
March 21, 2023 15:15
-
-
Save coolcomputery/e0204bc48abda3ff3ee9877aa808e7ca to your computer and use it in GitHub Desktop.
6x6 (Dijkstra's + "L-conjugations"): 4x4->4x6 GN<=20, 4x6->6x6 GN<=21
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% java -Xmx10g src/DijkstraRegion.java | |
6x6: [0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 18, 19, 20, 21] --> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] | |
#canonical_seqs=88 | |
canonical_seqs=[[4C], [3R, 4C, 3R'], [2R, 4C, 2R'], [1R, 4C, 1R'], [0R', 5C, 0R], [1R, 4C2, 1R'], [3R, 4C2, 3R'], [0R', 5C2, 0R], [2R, 4C2, 2R'], [1R, 4C3, 1R'], [2R, 4C3, 2R'], [0R', 5C3, 0R], [3R, 4C3, 3R'], [1R, 4C4, 1R'], [2R, 4C4, 2R'], [3R, 4C4, 3R'], [0R', 5C4, 0R], [1R, 4C', 1R'], [4C'], [3R, 4C', 3R'], [2R, 4C', 2R'], [0R', 5C', 0R], [0R, 4C, 0R'], [1R', 5C, 1R], [2R', 5C, 2R], [3R', 5C, 3R], [5C], [2R', 5C2, 2R], [0R, 4C2, 0R'], [3R', 5C2, 3R], [1R', 5C2, 1R], [3R', 5C3, 3R], [0R, 4C3, 0R'], [2R', 5C3, 2R], [1R', 5C3, 1R], [0R, 4C4, 0R'], [3R', 5C4, 3R], [2R', 5C4, 2R], [1R', 5C4, 1R], [0R, 4C', 0R'], [2R', 5C', 2R], [3R', 5C', 3R], [5C'], [1R', 5C', 1R], [5R], [5R'], [3C', 5R3, 3C], [3C', 5R4, 3C], [3C', 5R', 3C], [3C', 5R, 3C], [3C', 5R2, 3C], [2C', 5R4, 2C], [2C', 5R', 2C], [2C', 5R, 2C], [2C', 5R2, 2C], [2C', 5R3, 2C], [0C, 4R, 0C'], [0C, 4R2, 0C'], [0C, 4R3, 0C'], [0C, 4R4, 0C'], [0C, 4R', 0C'], [1C', 5R', 1C], [1C', 5R, 1C], [1C', 5R2, 1C], [1C', 5R3, 1C], [1C', 5R4, 1C], [4R], [3C, 4R, 3C'], [2C, 4R, 2C'], [1C, 4R2, 1C'], [3C, 4R2, 3C'], [1C, 4R3, 1C'], [2C, 4R3, 2C'], [1C, 4R4, 1C'], [3C, 4R4, 3C'], [2C, 4R4, 2C'], [4R'], [3C, 4R', 3C'], [2C, 4R', 2C'], [1C, 4R', 1C'], [0C', 5R, 0C], [1C, 4R, 1C'], [0C', 5R2, 0C], [2C, 4R2, 2C'], [0C', 5R3, 0C], [3C, 4R3, 3C'], [0C', 5R4, 0C], [0C', 5R', 0C]] | |
cost_freq={1=8, 3=32, 4=32, 5=16} | |
ri2loc=[4, 5, 10, 11, 16, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35] loc2ri=[-1, -1, -1, -1, 0, 1, -1, -1, -1, -1, 2, 3, -1, -1, -1, -1, 4, 5, -1, -1, -1, -1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] | |
bridge=[4, 5, 10, 11, 16, 17, 22, 23] | |
nconfigs=5079110400 | |
time=69 cnt=0 d=0 | |
time=12781 cnt=1 d=1 | |
time=25963 cnt=5 d=2 | |
time=30117 cnt=17 d=2 | |
time=40499 cnt=55 d=3 | |
time=50117 cnt=107 d=3 | |
time=60691 cnt=566 d=4 | |
time=70096 cnt=2700 d=5 | |
time=80040 cnt=9278 d=6 | |
time=90002 cnt=23945 d=7 | |
time=100000 cnt=67853 d=7 | |
time=200000 cnt=5557746 d=10 | |
time=300000 cnt=13969186 d=11 | |
time=400000 cnt=22276301 d=11 | |
time=500000 cnt=30118679 d=11 | |
time=600000 cnt=38106741 d=12 | |
time=700000 cnt=44004478 d=12 | |
time=800000 cnt=51843483 d=12 | |
time=900000 cnt=59580551 d=12 | |
time=1000000 cnt=67328948 d=12 | |
time=2000000 cnt=155420862 d=13 | |
time=3000000 cnt=244102814 d=13 | |
time=4000000 cnt=321616927 d=13 | |
time=5000000 cnt=402977221 d=14 | |
time=6000000 cnt=491848374 d=14 | |
time=7000000 cnt=574675136 d=14 | |
time=8000000 cnt=664965749 d=14 | |
time=9000000 cnt=749889274 d=14 | |
time=10000000 cnt=804581822 d=14 | |
time=11000000 cnt=855868896 d=14 | |
time=12000000 cnt=928483983 d=14 | |
time=13000000 cnt=1021836214 d=15 | |
time=14000000 cnt=1115548705 d=15 | |
time=15000001 cnt=1189639508 d=15 | |
time=16000000 cnt=1270327139 d=15 | |
time=17000000 cnt=1347818441 d=15 | |
time=18000000 cnt=1446946077 d=15 | |
time=19000000 cnt=1544599281 d=15 | |
time=20000000 cnt=1610347660 d=15 | |
time=21000000 cnt=1704843240 d=15 | |
time=22000000 cnt=1795375411 d=15 | |
time=23000000 cnt=1900015956 d=15 | |
time=24000000 cnt=1998762460 d=15 | |
time=25000000 cnt=2115941269 d=15 | |
time=26000000 cnt=2239954555 d=16 | |
time=27000000 cnt=2363267633 d=16 | |
time=28000000 cnt=2487609229 d=16 | |
time=29000000 cnt=2611673565 d=16 | |
time=30000000 cnt=2735050415 d=16 | |
time=31000000 cnt=2859799777 d=16 | |
time=32000000 cnt=2984277032 d=16 | |
time=33000000 cnt=3110891863 d=16 | |
time=34000000 cnt=3238314707 d=16 | |
time=35000000 cnt=3365449975 d=16 | |
time=36000000 cnt=3492512775 d=16 | |
time=37000000 cnt=3616630336 d=17 | |
time=38000000 cnt=3739857938 d=17 | |
time=39000000 cnt=3861622383 d=17 | |
time=40000000 cnt=3980536869 d=17 | |
time=41000000 cnt=4099187094 d=17 | |
time=42000000 cnt=4220472281 d=17 | |
time=43000000 cnt=4347363326 d=17 | |
time=44000000 cnt=4474249478 d=17 | |
time=45000000 cnt=4599099437 d=17 | |
time=46000000 cnt=4717302598 d=18 | |
time=47000000 cnt=4826975967 d=18 | |
time=48000000 cnt=4941746984 d=18 | |
time=49000000 cnt=5054363461 d=19 | |
time=49295192 cnt=5079110400 | |
diameter=20 | |
depth_freq={0=1, 1=4, 2=16, 3=90, 4=492, 5=2474, 6=12259, 7=59574, 8=283163, 9=1300242, 10=5666906, 11=22913610, 12=82863149, 13=254076682, 14=621818069, 15=1141541684, 16=1437263840, 17=1090325622, 18=390839599, 19=30045083, 20=97841} | |
sample antipode: | |
. . . . 18 . | |
. . . . . . | |
. . . . . . | |
. . . . . 17 | |
. . 24 23 . 5 | |
6 11 . 12 . . | |
sol (right-to-left): [[5C'], [1R, 4C, 1R'], [5C'], [5R], [4C], [4R], [5R], [4C], [5R], [4C], [4C], [4R], [5C'], [5C'], [5R], [5R], [5C], [4C]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
public class DijkstraRegion { | |
public static final boolean inRange(int v, int N) { return 0<=v && v<N; } | |
public static final boolean inRange(long v, long N) { return 0<=v && v<N; } | |
public static final boolean allInRange(int[] S, int N) { | |
for (int v:S) if (!inRange(v,N)) return false; | |
return true; | |
} | |
public static final int[] range(int n) { | |
int[] out=new int[n]; | |
for (int i=0; i<n; i++) out[i]=i; | |
return out; | |
} | |
public static final int[] list2arr(List<Integer> L) { | |
int[] A=new int[L.size()]; | |
for (int i=0; i<A.length; i++) A[i]=L.get(i); | |
return A; | |
} | |
public static final int[] sortedArr(Set<Integer> S) { | |
List<Integer> vals=new ArrayList<>(S); | |
Collections.sort(vals); | |
return list2arr(vals); | |
} | |
public static int[][] fromto_idx(Set<Integer> S, int N) { | |
for (int v:S) if (!inRange(v,N)) throw new RuntimeException(); | |
int[] idx2set=sortedArr(S); | |
final int INVALID=-1; | |
int[] set2idx=new int[N]; Arrays.fill(set2idx,INVALID); | |
for (int i=0; i<idx2set.length; i++) | |
set2idx[idx2set[i]]=i; | |
return new int[][] {idx2set,set2idx}; | |
} | |
public static final Set<Integer> set(int... vals) { | |
Set<Integer> out=new HashSet<>(); | |
for (int v:vals) out.add(v); | |
return out; | |
} | |
public static final Set<Integer> difference(Set<Integer> A, Collection<Integer> B) { | |
Set<Integer> out=new HashSet<>(A); | |
out.removeAll(B); | |
return out; | |
} | |
private static class BigByteArray { | |
private static final int CHUNK_SIZE=1<<30; | |
public final long N; | |
public byte[][] chunks; | |
public BigByteArray(long N, int val) { | |
if (val!=(byte)val) throw new RuntimeException(""+val); | |
this.N=N; | |
chunks=new byte[(int)(N/CHUNK_SIZE)+1][]; | |
for (int c=0; CHUNK_SIZE*(long)c<N; c++) { | |
long lo=CHUNK_SIZE*(long)c; | |
chunks[c]=new byte[(int)( Math.min(N,lo+CHUNK_SIZE)-lo )]; | |
} | |
for (byte[] chunk:chunks) Arrays.fill(chunk,(byte)val); | |
} | |
public byte get(long i) { | |
if (!inRange(i,N)) throw new RuntimeException(); | |
return chunks[(int)(i/CHUNK_SIZE)][(int)(i%CHUNK_SIZE)]; | |
} | |
public void set(long i, int v) { | |
if (!inRange(i,N)) throw new RuntimeException(); | |
if (v!=(byte)v) throw new RuntimeException(""+v); | |
chunks[(int)(i/CHUNK_SIZE)][(int)(i%CHUNK_SIZE)]=(byte)v; | |
} | |
} | |
private static final int[] prod(int[] A, int[] B) { | |
int[] C=new int[B.length]; | |
for (int i=0; i<B.length; i++) C[i]=A[B[i]]; | |
return C; | |
} | |
private static class Move { //single-move permutation on a RxC loopover board | |
public static final int mod(int n, int k) { return ((n%k)+k)%k; } | |
public final int R, C, N; | |
public final boolean row_shift; | |
public final int coord, shift; | |
public Move(int R, int C, boolean row_shift, int coord, int shift) { | |
if (R<=0 || C<=0) throw new RuntimeException(); | |
if (!inRange(coord,row_shift?R:C)) throw new RuntimeException(); | |
this.R=R; this.C=C; N=R*C; | |
this.row_shift=row_shift; | |
this.coord=coord; | |
this.shift=mod(shift,row_shift?C:R); | |
if (!inRange(this.shift,row_shift?C:R)) throw new RuntimeException(); | |
} | |
public boolean same_dimensions(Move o) { | |
return R==o.R && C==o.C; | |
} | |
public Move inv() { | |
return new Move(R,C,row_shift,coord,-shift); | |
} | |
public int cost() { | |
return Math.min(shift,(row_shift?C:R)-shift); | |
} | |
public int move(int v) { | |
if (!inRange(v,N)) throw new RuntimeException(); | |
int r=v/C, c=mod(v,C); | |
if (row_shift) { | |
if (coord==r) c=mod(c+shift,C); | |
} | |
else { | |
if (coord==c) r=mod(r+shift,R); | |
} | |
return r*C+c; | |
} | |
public int[] action() { | |
int[] out=new int[N]; | |
for (int i=0; i<N; i++) out[i]=move(i); | |
return out; | |
} | |
public String toString() { | |
return String.format("%d%s%s", | |
coord, | |
row_shift?"R":"C", | |
shift==1?"":shift==mod(-1,row_shift?C:R)?"'":shift | |
); | |
} | |
public static int cost(Iterable<Move> mvs) { | |
int out=0; | |
for (Move mv:mvs) out+=mv.cost(); | |
return out; | |
} | |
public static List<Move> inv(List<Move> mvs) { | |
List<Move> out=new ArrayList<>(); | |
for (int i=mvs.size()-1; i>=0; i--) | |
out.add(mvs.get(i).inv()); | |
return out; | |
} | |
public static int[] action(List<Move> mvs) { | |
for (int i=1; i<mvs.size(); i++) | |
if (!mvs.get(0).same_dimensions(mvs.get(i))) throw new RuntimeException(); | |
int[] out=range(mvs.get(0).N); | |
for (Move mv:mvs) out=prod(out,mv.action()); | |
return out; | |
} | |
} | |
public static String display(int R, int C, int[] pcs, int[] locs) { | |
if (pcs.length!=locs.length) throw new RuntimeException(); | |
final int BLANK=-1; | |
int[] board=new int[R*C]; Arrays.fill(board,BLANK); | |
for (int i=0; i<pcs.length; i++) | |
board[locs[i]]=pcs[i]; | |
boolean alphaMode=R*C<=26; | |
int CHARS_PER_CELL=alphaMode?1:(1+(R*C+"").length()); | |
String CELL_FORMAT="%"+CHARS_PER_CELL+"s"; | |
StringBuilder s=new StringBuilder(); | |
for (int loc=0; loc<R*C; loc++) { | |
int pc=board[loc]; | |
s.append( | |
String.format(CELL_FORMAT, | |
pc==BLANK? ".": alphaMode? (""+(char)('A'+pc)): (pc+1) | |
) | |
).append(loc%C==C-1?"\n":""); | |
} | |
return s.substring(0,s.length()-1); | |
} | |
//bijection {K-length lists of numbers in [0,N)} <--> [0,(N choose K)*K!) | |
//must have (N choose K)*K! < Integer.MAX_VALUE for these methods to work properly | |
private static final long perm2code(int N, int[] P) { | |
//transform list L=[0,...,N-1] to [....]|P using swaps (i,J_i) for i=N-1...N-K; | |
// then encode [J_{N-1},...J_{N-K}] as a number using mixed-radix valuation | |
if (!allInRange(P,N)) throw new RuntimeException(); | |
int[] L=range(N), locInL=range(N); | |
int K=P.length; | |
long out=0, pow=1; | |
for (int i=N-1, pi=K-1; i>=N-K; i--, pi--) { | |
int j=locInL[P[pi]]; | |
int Li=L[i], Lj=L[j]; | |
if (Lj!=P[pi]) throw new RuntimeException(); | |
L[i]=Lj; L[j]=Li; | |
locInL[Li]=j; locInL[Lj]=i; | |
out+=j*pow; | |
pow*=(i+1); | |
} | |
return out; | |
} | |
private static final int[] code2perm(int N, int K, long code) { | |
int[] L=range(N); | |
for (int i=N-1; i>=N-K; i--) { | |
int j=(int)(code%(i+1)); | |
int Li=L[i], Lj=L[j]; | |
L[i]=Lj; L[j]=Li; | |
code/=(i+1); | |
} | |
if (code!=0) throw new RuntimeException(""+code); | |
return Arrays.copyOfRange(L,N-K,N); | |
} | |
public static void dijkstra(int R, int C, int[] start, int[] end, List<List<Move>> seqs0) { | |
System.out.printf("%dx%d: %s --> %s%n",R,C,Arrays.toString(start),Arrays.toString(end)); | |
if (!allInRange(start,R*C) || !allInRange(end,R*C)) throw new RuntimeException(); | |
for (List<Move> seq:seqs0) for (Move mv:seq) if (mv.R!=R || mv.C!=C) throw new RuntimeException(); | |
int nActs; List<List<Move>> canonical_seqs; int[][] canonical_acts; int[] canonical_costs; { | |
int[] ID_ACT=range(R*C); | |
Map<String,List<Move>> act2seq=new HashMap<>(); | |
for (boolean inv:new boolean[] {false,true}) | |
for (List<Move> seq0:seqs0) { | |
List<Move> seq=inv?Move.inv(seq0):seq0; | |
int[] act=Move.action(seq); | |
//every action we use must preserve every element in the start array | |
// and not be equal to the identity (do-nothing) action | |
if (Arrays.equals(prod(act,start),start) && !Arrays.equals(act,ID_ACT)) { | |
String act_s=Arrays.toString(act); | |
if (!act2seq.containsKey(act_s) | |
|| Move.cost(seq)<Move.cost(act2seq.get(act_s))) | |
act2seq.put(act_s,seq); | |
} | |
} | |
List<String> act_ss=new ArrayList<>(act2seq.keySet()); | |
Collections.sort(act_ss); | |
canonical_seqs=new ArrayList<>(); | |
for (String act_s:act_ss) | |
canonical_seqs.add(act2seq.get(act_s)); | |
System.out.printf("#canonical_seqs=%d%n",canonical_seqs.size()); | |
System.out.printf("canonical_seqs=%s%n",canonical_seqs); | |
for (List<Move> seq:canonical_seqs) { | |
int[] act=Move.action(seq); | |
if (!Arrays.equals(prod(act,start),start)) | |
throw new RuntimeException(); | |
} | |
nActs=canonical_seqs.size(); | |
canonical_acts=new int[nActs][]; canonical_costs=new int[nActs]; | |
for (int i=0; i<nActs; i++) { | |
List<Move> seq=canonical_seqs.get(i); | |
canonical_acts[i]=Move.action(seq); | |
canonical_costs[i]=Move.cost(seq); | |
} | |
Map<Integer,Integer> cost_freq=new TreeMap<>(); | |
for (List<Move> seq:canonical_seqs) { | |
int c=Move.cost(seq); | |
cost_freq.put(c,cost_freq.getOrDefault(c,0)+1); | |
} | |
System.out.printf("cost_freq=%s%n",cost_freq); | |
} | |
int N=R*C; | |
int[] ri2loc, loc2ri; { | |
int[][] fromto=fromto_idx(difference(set(range(N)),set(start)),N); | |
ri2loc=fromto[0]; loc2ri=fromto[1]; | |
System.out.printf("ri2loc=%s loc2ri=%s%n",Arrays.toString(ri2loc),Arrays.toString(loc2ri)); | |
} | |
class Config2Code { | |
public final int nRem=N-start.length, nBridge=end.length-start.length; | |
public long config2code(int[] config) { | |
if (config.length!=nBridge) throw new RuntimeException(); | |
return perm2code(nRem,prod(loc2ri,config)); | |
} | |
public int[] code2config(long code) { | |
return prod(ri2loc,code2perm(nRem,nBridge,code)); | |
} | |
} Config2Code $=new Config2Code(); | |
//assert that set(end) is a strict superset of set(start) | |
if (difference(set(start),set(end)).size()!=0 || end.length<=start.length) throw new RuntimeException(); | |
int[] bridge=sortedArr(difference(set(end),set(start))); | |
System.out.printf("bridge=%s%n",Arrays.toString(bridge)); | |
long nconfigs=1; for (int i=N-start.length; i>N-end.length; i--) nconfigs*=i; | |
System.out.printf("nconfigs=%d%n",nconfigs); | |
if (nconfigs>=(1L<<40)) throw new RuntimeException(); | |
int INVALID_DEPTH=-1; | |
BigByteArray depths=new BigByteArray(nconfigs,INVALID_DEPTH); { | |
long solved_code=$.config2code(bridge); | |
depths.set(solved_code,0); | |
} | |
long cnt=0; | |
long st=System.currentTimeMillis(), mark=0; | |
for (int d=0;; d++) { | |
if (d>Byte.MAX_VALUE) throw new RuntimeException(); | |
for (long code=0; code<nconfigs; code++) | |
if (depths.get(code)==d) { | |
long t=System.currentTimeMillis()-st; | |
if (t>=mark) { | |
System.out.printf("time=%d cnt=%d d=%d%n",t,cnt,d); | |
mark+=mark<100_000?10_000:mark<1000_000?100_000:1000_000; | |
} | |
int[] config=$.code2config(code); | |
for (int m=0; m<nActs; m++) { | |
long ncode=$.config2code(prod(canonical_acts[m],config)); | |
int od=depths.get(ncode), nd=d+canonical_costs[m]; | |
if (od==INVALID_DEPTH || nd<od) | |
depths.set(ncode,nd); | |
} | |
cnt++; | |
} | |
boolean finished=true; | |
for (long code=0; code<nconfigs; code++) { | |
int depth=depths.get(code); | |
if (depth!=INVALID_DEPTH && depth>=d) { | |
finished=false; | |
break; | |
} | |
} | |
if (finished) break; | |
} | |
System.out.printf("time=%d cnt=%d%n",System.currentTimeMillis()-st,cnt); | |
if (cnt!=nconfigs) | |
System.out.printf("WARNING: # of configs found=%d != %d=expected # of configs%s%n", | |
cnt,nconfigs,2*cnt==nconfigs?" (parity restriction?)":""); | |
int diam=0; | |
Map<Integer,Integer> depth_freq=new TreeMap<>(); | |
for (long code=0; code<nconfigs; code++) { | |
int d=depths.get(code); | |
if (d!=INVALID_DEPTH) { | |
diam=Math.max(diam,d); | |
depth_freq.put(d,depth_freq.getOrDefault(d,0)+1); | |
} | |
} | |
System.out.printf("diameter=%d%ndepth_freq=%s%n",diam,depth_freq); | |
//print an antipode | |
class Solver { | |
public List<List<Move>> sol(long code) { | |
if (depths.get(code)==INVALID_DEPTH) throw new RuntimeException(); | |
List<List<Move>> out=new ArrayList<>(); | |
while (depths.get(code)>0) { | |
int[] config=$.code2config(code); | |
long bcode=-1; List<Move> bseq=null; | |
for (int m=0; m<nActs; m++) { | |
long ncode=$.config2code(prod(canonical_acts[m],config)); | |
if (depths.get(ncode)+canonical_costs[m]==depths.get(code)) { | |
bcode=ncode; | |
bseq=canonical_seqs.get(m); | |
break; | |
} | |
} | |
if (bseq==null) throw new RuntimeException(); | |
code=bcode; | |
out.add(bseq); | |
} | |
Collections.reverse(out); //use right-to-left convention (apply rightmost move, then left-most, etc. | |
//this is so that we match the reading convention within each sequence element of out | |
return out; | |
} | |
} Solver S$=new Solver(); | |
System.out.println("sample antipode:"); | |
for (long code=0; code<nconfigs; code++) | |
if (depths.get(code)==diam) { | |
System.out.println(display(R,C,bridge,$.code2config(code))+"\nsol (right-to-left): "+S$.sol(code)); | |
break; | |
} | |
} | |
public static List<List<Move>> singleMoves(int R, int C) { | |
List<List<Move>> out=new ArrayList<>(); | |
for (boolean row_shift:new boolean[] {true,false}) | |
for (int coord=0; coord<(row_shift?R:C); coord++) | |
for (int shift:new int[] {-1,1}) | |
out.add(Collections.singletonList(new Move(R,C,row_shift,coord,shift))); | |
return out; | |
} | |
public static void dijkstra(int R, int C, int[] start, int[] end) { | |
dijkstra(R,C,start,end,singleMoves(R,C)); | |
} | |
public static List<List<Move>> Lconjugations(int R, int C, int[] region) { | |
boolean[] rowCovered=new boolean[R], clmCovered=new boolean[C]; | |
for (int i:region) { | |
rowCovered[i/C]=true; | |
clmCovered[i%C]=true; | |
} | |
List<List<Move>> out=new ArrayList<>(singleMoves(R,C)); | |
for (boolean conj_dim:new boolean[] {false,true}) | |
for (int co=0; co<(conj_dim?R:C); co++) | |
if ((conj_dim?rowCovered:clmCovered)[co]) | |
for (int co_sh=0; co_sh<(conj_dim?C:R); co_sh++) if (co_sh!=0) { | |
Move j=new Move(R,C,conj_dim,co,co_sh); | |
for (int sco=0; sco<(conj_dim?C:R); sco++) | |
for (int ssh=0; ssh<(conj_dim?R:C); ssh++) | |
out.add(Arrays.asList(j,new Move(R,C,!conj_dim,sco,ssh),j.inv())); | |
} | |
return out; | |
} | |
public static void dijkstra_Lconj(int R, int C, int[] start, int[] end) { | |
dijkstra(R,C,start,end,Lconjugations(R,C,start)); | |
} | |
public static void main(String[] args) { | |
int R=6, C=6; | |
class RegionHelp { | |
public int[] blockRegion(int[] rs, int[] cs) { | |
Set<Integer> S=new HashSet<>(); | |
for (int r:rs) for (int c:cs) S.add(r*C+c); | |
return sortedArr(S); | |
} | |
public int[] blockRegion(int[] rs) { | |
return blockRegion(rs,rs); | |
} | |
} RegionHelp $=new RegionHelp(); | |
dijkstra_Lconj(R,C,$.blockRegion(range(4)),$.blockRegion(range(4),range(6))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6x6: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] --> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35] | |
cost_freq={1=4, 2=4, 3=26, 4=24, 5=72, 6=60, 7=70, 8=40, 9=20} | |
ri2loc=[24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35] loc2ri=[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] | |
bridge=[24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35] | |
nconfigs=479001600 | |
time=320 cnt=0 d=0 | |
time=10002 cnt=2806 d=6 | |
time=20000 cnt=106688 d=9 | |
time=30000 cnt=257775 d=10 | |
time=40000 cnt=424177 d=10 | |
time=50000 cnt=589686 d=10 | |
time=60000 cnt=759268 d=10 | |
time=70000 cnt=942680 d=11 | |
time=80000 cnt=1137018 d=11 | |
time=90000 cnt=1334102 d=11 | |
time=100000 cnt=1529923 d=11 | |
time=200000 cnt=3443149 d=12 | |
time=300000 cnt=5405655 d=12 | |
time=400000 cnt=7390190 d=12 | |
time=500000 cnt=9509950 d=13 | |
time=600000 cnt=11696146 d=13 | |
time=700000 cnt=13925305 d=13 | |
time=800000 cnt=16115873 d=13 | |
time=900000 cnt=18347065 d=13 | |
time=1000000 cnt=20558584 d=13 | |
time=2000000 cnt=44269042 d=14 | |
time=3000000 cnt=68253781 d=14 | |
time=4000000 cnt=93602992 d=15 | |
time=5000000 cnt=118971500 d=15 | |
time=6000000 cnt=144366871 d=15 | |
time=7000000 cnt=169854458 d=16 | |
time=8000000 cnt=195774880 d=16 | |
time=9000000 cnt=221817741 d=16 | |
time=10000000 cnt=247844197 d=16 | |
time=11000000 cnt=273867968 d=16 | |
time=12000000 cnt=299822744 d=16 | |
time=13000000 cnt=325729260 d=17 | |
time=14000000 cnt=351530408 d=17 | |
time=15000000 cnt=377248787 d=17 | |
time=16000000 cnt=403043068 d=17 | |
time=17000000 cnt=428763641 d=18 | |
time=18000000 cnt=453206939 d=18 | |
time=19000000 cnt=476835156 d=19 | |
time=19111965 cnt=479001600 | |
diameter=21 | |
depth_freq={0=1, 1=4, 2=8, 3=34, 4=224, 5=892, 6=2965, 7=11110, 8=44124, 9=159060, 10=541924, 11=1801924, 12=5901323, 13=17132692, 14=44359213, 15=96249480, 16=141263572, 17=119398514, 18=47277902, 19=4745530, 20=109544, 21=1560} | |
Process finished with exit code 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
public class DijkstraRegion { | |
public static final boolean inRange(int v, int N) { return 0<=v && v<N; } | |
public static final boolean allInRange(int[] S, int N) { | |
for (int v:S) if (!inRange(v,N)) return false; | |
return true; | |
} | |
public static final int[] range(int n) { | |
int[] out=new int[n]; | |
for (int i=0; i<n; i++) out[i]=i; | |
return out; | |
} | |
public static final int[] list2arr(List<Integer> L) { | |
int[] A=new int[L.size()]; | |
for (int i=0; i<A.length; i++) A[i]=L.get(i); | |
return A; | |
} | |
public static final int[] sortedArr(Set<Integer> S) { | |
List<Integer> vals=new ArrayList<>(S); | |
Collections.sort(vals); | |
return list2arr(vals); | |
} | |
public static int[][] fromto_idx(Set<Integer> S, int N) { | |
for (int v:S) if (!inRange(v,N)) throw new RuntimeException(); | |
int[] idx2set=sortedArr(S); | |
final int INVALID=-1; | |
int[] set2idx=new int[N]; Arrays.fill(set2idx,INVALID); | |
for (int i=0; i<idx2set.length; i++) | |
set2idx[idx2set[i]]=i; | |
return new int[][] {idx2set,set2idx}; | |
} | |
public static final Set<Integer> set(int... vals) { | |
Set<Integer> out=new HashSet<>(); | |
for (int v:vals) out.add(v); | |
return out; | |
} | |
public static final Set<Integer> difference(Set<Integer> A, Collection<Integer> B) { | |
Set<Integer> out=new HashSet<>(A); | |
out.removeAll(B); | |
return out; | |
} | |
private static final int[] prod(int[] A, int[] B) { | |
int[] C=new int[B.length]; | |
for (int i=0; i<B.length; i++) C[i]=A[B[i]]; | |
return C; | |
} | |
private static class Move { //single-move permutation on a RxC loopover board | |
public static final int mod(int n, int k) { return ((n%k)+k)%k; } | |
public final int R, C, N; | |
public final boolean row_shift; | |
public final int coord, shift; | |
public Move(int R, int C, boolean row_shift, int coord, int shift) { | |
if (R<=0 || C<=0) throw new RuntimeException(); | |
if (!inRange(coord,row_shift?R:C)) throw new RuntimeException(); | |
this.R=R; this.C=C; N=R*C; | |
this.row_shift=row_shift; | |
this.coord=coord; | |
this.shift=mod(shift,row_shift?C:R); | |
if (!inRange(this.shift,row_shift?C:R)) throw new RuntimeException(); | |
} | |
public boolean same_dimensions(Move o) { | |
return R==o.R && C==o.C; | |
} | |
public Move inv() { | |
return new Move(R,C,row_shift,coord,-shift); | |
} | |
public int cost() { | |
return Math.min(shift,(row_shift?C:R)-shift); | |
} | |
public int move(int v) { | |
if (!inRange(v,N)) throw new RuntimeException(); | |
int r=v/C, c=mod(v,C); | |
if (row_shift) { | |
if (coord==r) c=mod(c+shift,C); | |
} | |
else { | |
if (coord==c) r=mod(r+shift,R); | |
} | |
return r*C+c; | |
} | |
public int[] action() { | |
int[] out=new int[N]; | |
for (int i=0; i<N; i++) out[i]=move(i); | |
return out; | |
} | |
public String toString() { | |
return String.format("%d%s%s", | |
coord, | |
row_shift?"R":"C", | |
shift==1?"":shift==mod(-1,row_shift?C:R)?"'":shift | |
); | |
} | |
public static int cost(Iterable<Move> mvs) { | |
int out=0; | |
for (Move mv:mvs) out+=mv.cost(); | |
return out; | |
} | |
public static List<Move> inv(List<Move> mvs) { | |
List<Move> out=new ArrayList<>(); | |
for (int i=mvs.size()-1; i>=0; i--) | |
out.add(mvs.get(i).inv()); | |
return out; | |
} | |
public static int[] action(List<Move> mvs) { | |
for (int i=1; i<mvs.size(); i++) | |
if (!mvs.get(0).same_dimensions(mvs.get(i))) throw new RuntimeException(); | |
int[] out=range(mvs.get(0).N); | |
for (Move mv:mvs) out=prod(out,mv.action()); | |
return out; | |
} | |
} | |
//bijection {K-length lists of numbers in [0,N)} <--> [0,(N choose K)*K!) | |
//must have (N choose K)*K! < Integer.MAX_VALUE for these methods to work properly | |
private static final long perm2code(int N, int[] P) { | |
//transform list L=[0,...,N-1] to [....]|P using swaps (i,J_i) for i=N-1...N-K; | |
// then encode [J_{N-1},...J_{N-K}] as a number using mixed-radix valuation | |
if (!allInRange(P,N)) throw new RuntimeException(); | |
int[] L=range(N), locInL=range(N); | |
int K=P.length; | |
long out=0, pow=1; | |
for (int i=N-1, pi=K-1; i>=N-K; i--, pi--) { | |
int j=locInL[P[pi]]; | |
int Li=L[i], Lj=L[j]; | |
if (Lj!=P[pi]) throw new RuntimeException(); | |
L[i]=Lj; L[j]=Li; | |
locInL[Li]=j; locInL[Lj]=i; | |
out+=j*pow; | |
pow*=(i+1); | |
} | |
return out; | |
} | |
private static final int[] code2perm(int N, int K, long code) { | |
int[] L=range(N); | |
for (int i=N-1; i>=N-K; i--) { | |
int j=(int)(code%(i+1)); | |
int Li=L[i], Lj=L[j]; | |
L[i]=Lj; L[j]=Li; | |
code/=(i+1); | |
} | |
if (code!=0) throw new RuntimeException(""+code); | |
return Arrays.copyOfRange(L,N-K,N); | |
} | |
public static void dijkstra(int R, int C, int[] start, int[] end, List<List<Move>> seqs0) { | |
System.out.printf("%dx%d: %s --> %s%n",R,C,Arrays.toString(start),Arrays.toString(end)); | |
if (!allInRange(start,R*C) || !allInRange(end,R*C)) throw new RuntimeException(); | |
for (List<Move> seq:seqs0) for (Move mv:seq) if (mv.R!=R || mv.C!=C) throw new RuntimeException(); | |
int nActs; int[][] canonical_acts; int[] canonical_costs; { | |
int[] ID_ACT=range(R*C); | |
Map<String,List<Move>> act2seq=new HashMap<>(); | |
for (boolean inv:new boolean[] {false,true}) | |
for (List<Move> seq0:seqs0) { | |
List<Move> seq=inv?Move.inv(seq0):seq0; | |
int[] act=Move.action(seq); | |
//every action we use must preserve every element in the start array | |
// and not be equal to the identity (do-nothing) action | |
if (Arrays.equals(prod(act,start),start) && !Arrays.equals(act,ID_ACT)) { | |
String act_s=Arrays.toString(act); | |
if (!act2seq.containsKey(act_s) | |
|| Move.cost(seq)<Move.cost(act2seq.get(act_s))) | |
act2seq.put(act_s,seq); | |
} | |
} | |
List<String> act_ss=new ArrayList<>(act2seq.keySet()); | |
Collections.sort(act_ss); | |
List<List<Move>> canonical_seqs; | |
canonical_seqs=new ArrayList<>(); | |
for (String act_s:act_ss) | |
canonical_seqs.add(act2seq.get(act_s)); | |
for (List<Move> seq:canonical_seqs) { | |
int[] act=Move.action(seq); | |
if (!Arrays.equals(prod(act,start),start)) | |
throw new RuntimeException(); | |
} | |
nActs=canonical_seqs.size(); | |
canonical_acts=new int[nActs][]; canonical_costs=new int[nActs]; | |
for (int i=0; i<nActs; i++) { | |
List<Move> seq=canonical_seqs.get(i); | |
canonical_acts[i]=Move.action(seq); | |
canonical_costs[i]=Move.cost(seq); | |
} | |
Map<Integer,Integer> cost_freq=new TreeMap<>(); | |
for (List<Move> seq:canonical_seqs) { | |
int c=Move.cost(seq); | |
cost_freq.put(c,cost_freq.getOrDefault(c,0)+1); | |
} | |
System.out.printf("cost_freq=%s%n",cost_freq); | |
} | |
int N=R*C; | |
int[] ri2loc, loc2ri; { | |
int[][] fromto=fromto_idx(difference(set(range(N)),set(start)),N); | |
ri2loc=fromto[0]; loc2ri=fromto[1]; | |
System.out.printf("ri2loc=%s loc2ri=%s%n",Arrays.toString(ri2loc),Arrays.toString(loc2ri)); | |
} | |
class Config2Code { | |
public final int nRem=N-start.length, nBridge=end.length-start.length; | |
public long config2code(int[] config) { | |
if (config.length!=nBridge) throw new RuntimeException(); | |
return perm2code(nRem,prod(loc2ri,config)); | |
} | |
public int[] code2config(long code) { | |
return prod(ri2loc,code2perm(nRem,nBridge,code)); | |
} | |
} Config2Code $=new Config2Code(); | |
//assert that set(end) is a strict superset of set(start) | |
if (difference(set(start),set(end)).size()!=0 || end.length<=start.length) throw new RuntimeException(); | |
int[] bridge=sortedArr(difference(set(end),set(start))); | |
System.out.printf("bridge=%s%n",Arrays.toString(bridge)); | |
long nconfigs=1; for (int i=N-start.length; i>N-end.length; i--) nconfigs*=i; | |
System.out.printf("nconfigs=%d%n",nconfigs); | |
if (nconfigs>=Integer.MAX_VALUE) throw new RuntimeException(); | |
int INVALID_DEPTH=Integer.MAX_VALUE; | |
int[] depths=new int[(int)nconfigs]; | |
Arrays.fill(depths,INVALID_DEPTH); { | |
long solved_code=$.config2code(bridge); | |
depths[(int)solved_code]=0; | |
} | |
long cnt=0; | |
long st=System.currentTimeMillis(), mark=0; | |
for (int d=0;; d++) { | |
for (long code=0; code<nconfigs; code++) | |
if (depths[(int)code]==d) { | |
long t=System.currentTimeMillis()-st; | |
if (t>=mark) { | |
System.out.printf("time=%d cnt=%d d=%d%n",t,cnt,d); | |
mark+=mark<100_000?10_000:mark<1000_000?100_000:1000_000; | |
} | |
int[] config=$.code2config(code); | |
for (int m=0; m<nActs; m++) { | |
long ncode=$.config2code(prod(canonical_acts[m],config)); | |
int nd=d+canonical_costs[m]; | |
if (nd<depths[(int)ncode]) | |
depths[(int)ncode]=nd; | |
} | |
cnt++; | |
} | |
boolean finished=true; | |
for (int depth:depths) if (depth!=INVALID_DEPTH && depth>=d) { | |
finished=false; | |
break; | |
} | |
if (finished) break; | |
} | |
System.out.printf("time=%d cnt=%d%n",System.currentTimeMillis()-st,cnt); | |
if (cnt!=nconfigs) { | |
System.out.printf("WARNING: # of configs found=%d != %d=expected # of configs%s%n", | |
cnt,nconfigs, | |
2*cnt==nconfigs?" (parity restriction?)":"" | |
); | |
} | |
int diam=0; for (int d:depths) if (d!=INVALID_DEPTH) diam=Math.max(diam,d); | |
System.out.printf("diameter=%d%n",diam); | |
Map<Integer,Integer> depth_freq=new TreeMap<>(); | |
for (int d:depths) if (d!=INVALID_DEPTH) depth_freq.put(d,depth_freq.getOrDefault(d,0)+1); | |
System.out.printf("depth_freq=%s%n",depth_freq); | |
} | |
public static void dijkstra(int R, int C, int[] start, int[] end) { | |
List<List<Move>> singleMvSeqs=new ArrayList<>(); | |
for (boolean row_shift:new boolean[] {true,false}) | |
for (int coord=0; coord<(row_shift?R:C); coord++) | |
for (int shift:new int[] {-1,1}) | |
singleMvSeqs.add(Collections.singletonList(new Move(R,C,row_shift,coord,shift))); | |
dijkstra(R,C,start,end,singleMvSeqs); | |
} | |
public static void main(String[] args) { | |
int R=6, C=6; | |
List<List<Move>> comms=new ArrayList<>(); | |
for (int[] row_csh:new int[][] {{R-1,-1},{R-2,1}}) { | |
int r=row_csh[0], csh=row_csh[1]; | |
for (int mask=0; mask<(1<<C); mask++) { | |
List<Move> clm_shifts=new ArrayList<>(); | |
for (int c=0; c<C; c++) if (((mask>>>c)&1)!=0) | |
clm_shifts.add(new Move(R,C,false,c,csh)); | |
for (int rsh=0; rsh<C; rsh++) { | |
List<Move> comm=new ArrayList<>(clm_shifts); | |
comm.add(new Move(R,C,true,r,rsh)); | |
comm.addAll(Move.inv(clm_shifts)); | |
comms.add(comm); | |
} | |
} | |
} | |
dijkstra(R,C,range((R-2)*C),range(R*C),comms); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment