|
|
|
|
@@ -43,10 +43,10 @@ public record SwedishGenerator() {
|
|
|
|
|
public static final int MIN_LEN = 3;//Config.MIN_LEN;
|
|
|
|
|
public static final int MAX_TRIES_PER_SLOT = 700;//Config.MAX_TRIES_PER_SLOT;
|
|
|
|
|
public static final int STACK_SIZE = 128;
|
|
|
|
|
public static final char C_DASH = '\0';
|
|
|
|
|
public static final byte DASH = (byte) C_DASH;
|
|
|
|
|
public static final long RANGE_0_SIZE = (long) SIZE_MIN_1 - 0L + 1L;
|
|
|
|
|
public static final long RANGE_0_624 = 624L - 0L + 1L;
|
|
|
|
|
static final int PICK_NOT_DONE = -1;
|
|
|
|
|
static final int PICK_DONE = 0;
|
|
|
|
|
public static boolean isLo(int n) { return (n & 64) == 0; }
|
|
|
|
|
interface Bit1029 {
|
|
|
|
|
|
|
|
|
|
@@ -57,40 +57,18 @@ public record SwedishGenerator() {
|
|
|
|
|
static void clear(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] &= ~(1L << bitIndex); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AllArgsConstructor
|
|
|
|
|
public static class Pick {
|
|
|
|
|
|
|
|
|
|
public Slotinfo slot;
|
|
|
|
|
public int[] indices;
|
|
|
|
|
public int count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//@formatter:off
|
|
|
|
|
public static record Dict(DictEntry[] index, int length) { }
|
|
|
|
|
@AllArgsConstructor @NoArgsConstructor static class Assign { long w; }
|
|
|
|
|
@AllArgsConstructor @NoArgsConstructor static final class Assign { long w; }
|
|
|
|
|
public static final class FillStats { public double simplicity; }
|
|
|
|
|
@AllArgsConstructor public static final class Grid { public final byte[] g; public long lo, hi; }
|
|
|
|
|
public static record Dict(DictEntry[] index, int length) { }
|
|
|
|
|
public static record FillResult(boolean ok, long nodes, long backtracks, int lastMRV, long elapsed, FillStats stats) { }
|
|
|
|
|
public static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
|
|
|
|
|
//@formatter:on
|
|
|
|
|
@AllArgsConstructor
|
|
|
|
|
public static class Grid {
|
|
|
|
|
|
|
|
|
|
public final byte[] g;
|
|
|
|
|
public long lo, hi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static record FillResult(boolean ok, long nodes, long backtracks, int lastMRV, long elapsed, FillStats stats) { }
|
|
|
|
|
|
|
|
|
|
public static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
|
|
|
|
|
|
|
|
|
|
public static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSETS_D_IDX;
|
|
|
|
|
public static final long[] NBR8_PACKED_LO = Neighbors9x8.NBR8_PACKED_LO;
|
|
|
|
|
public static final long[] NBR8_PACKED_HI = Neighbors9x8.NBR8_PACKED_HI;
|
|
|
|
|
|
|
|
|
|
public static final long[] PATH_LO = Neighbors9x8.PATH_LO;
|
|
|
|
|
public static final long[] PATH_HI = Neighbors9x8.PATH_HI;
|
|
|
|
|
|
|
|
|
|
public static final Pick PICK_DONE = null;//new Pick(null, null, 0, true);
|
|
|
|
|
|
|
|
|
|
public static final Pick PICK_NOT_DONE = new Pick(null, null, 0);
|
|
|
|
|
public static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSETS_D_IDX;
|
|
|
|
|
public static final long[] PATH_LO = Neighbors9x8.PATH_LO;
|
|
|
|
|
public static final long[] PATH_HI = Neighbors9x8.PATH_HI;
|
|
|
|
|
|
|
|
|
|
public static final class Rng {
|
|
|
|
|
|
|
|
|
|
@@ -111,12 +89,11 @@ public record SwedishGenerator() {
|
|
|
|
|
public byte randint2bitByte() {
|
|
|
|
|
int r = nextU32() & 7;
|
|
|
|
|
if (r == 4) return (byte) 4;
|
|
|
|
|
//if (r < 4) return (byte) r;
|
|
|
|
|
return (byte) (r & 3);
|
|
|
|
|
}
|
|
|
|
|
public <T> T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length /*- 0L*/ /*+ 1L*/)))]; }
|
|
|
|
|
public <T> T rand(List<T> p) { return p.get((int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.size() /*- 0L*/ /*+ 1L*/)))); }
|
|
|
|
|
public int randint(int max) { return (int) (((nextU32() & 0xFFFFFFFFL) % ((long) max /*- 0L*/ /*+ 1L*/))); }
|
|
|
|
|
public <T> T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; }
|
|
|
|
|
public <T> T rand(List<T> p) { return p.get((int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.size())))); }
|
|
|
|
|
public int randint(int max) { return (int) (((nextU32() & 0xFFFFFFFFL) % ((long) max))); }
|
|
|
|
|
public int randint0_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); }
|
|
|
|
|
public int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); }
|
|
|
|
|
public double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
|
|
|
|
@@ -140,9 +117,7 @@ public record SwedishGenerator() {
|
|
|
|
|
static int length0(long word) { return ((63 - numberOfLeadingZeros(word & LETTER_MASK)) / 5); }
|
|
|
|
|
public static String asWord(long word, byte[] bytes) {
|
|
|
|
|
int bi = 0;
|
|
|
|
|
for (long w = word & LETTER_MASK; w != 0; w >>>= 5) {
|
|
|
|
|
bytes[bi++] = (byte) ((w & 31) | 64); // neem laagste 5 bits
|
|
|
|
|
}
|
|
|
|
|
for (long w = word & LETTER_MASK; w != 0; w >>>= 5) bytes[bi++] = (byte) ((w & 31) | 64);
|
|
|
|
|
return new String(bytes, 0, bi, US_ASCII);
|
|
|
|
|
}
|
|
|
|
|
static int unpackIndex(long w) { return (int) (w >>> 40); }
|
|
|
|
|
@@ -164,7 +139,7 @@ public record SwedishGenerator() {
|
|
|
|
|
lo |= slot.lo;
|
|
|
|
|
hi |= slot.hi;
|
|
|
|
|
}
|
|
|
|
|
return new Grid(new byte[SIZE], ~lo, ~hi /*& 0xFF*/);
|
|
|
|
|
return new Grid(new byte[SIZE], ~lo, ~hi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -229,19 +204,18 @@ public record SwedishGenerator() {
|
|
|
|
|
|
|
|
|
|
public static FillResult fillMask(final Rng rng, final Slotinfo[] slots,
|
|
|
|
|
final Grid grid) {
|
|
|
|
|
val used = new long[2048];
|
|
|
|
|
val bitset = new long[2500];
|
|
|
|
|
val g = grid.g;
|
|
|
|
|
val TOTAL = slots.length;
|
|
|
|
|
val t0 = System.currentTimeMillis();
|
|
|
|
|
val CARRIER = new Pick(null, null, 0);
|
|
|
|
|
val used = new long[2048];
|
|
|
|
|
val bitset = new long[2500];
|
|
|
|
|
val g = grid.g;
|
|
|
|
|
val TOTAL = slots.length;
|
|
|
|
|
val t0 = System.currentTimeMillis();
|
|
|
|
|
class Solver {
|
|
|
|
|
|
|
|
|
|
long nodes;
|
|
|
|
|
long backtracks;
|
|
|
|
|
int lastMRV;
|
|
|
|
|
long lastLog = t0, glo = grid.lo, ghi = grid.hi;
|
|
|
|
|
Pick current = CARRIER;
|
|
|
|
|
long glo = grid.lo, ghi = grid.hi;
|
|
|
|
|
Slotinfo currentSlot;
|
|
|
|
|
int[] currentIndices;
|
|
|
|
|
boolean placeWordDec(final long lo, final long hi, final long w) {
|
|
|
|
|
int idx;
|
|
|
|
|
int bcHi = bitCount(hi);
|
|
|
|
|
@@ -274,19 +248,17 @@ public record SwedishGenerator() {
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
void chooseMRV() {
|
|
|
|
|
Slotinfo best = null;
|
|
|
|
|
for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) {
|
|
|
|
|
int chooseMRV() {
|
|
|
|
|
Slotinfo best = null;
|
|
|
|
|
int count2 = -1, bestScore = -1;
|
|
|
|
|
for (int i = 0, n = TOTAL; i < n; i++) {
|
|
|
|
|
var s = slots[i];
|
|
|
|
|
if (s.assign.w != X) continue;
|
|
|
|
|
var pattern = patternForSlot(glo, ghi, g, s.key, s.lo, s.hi);
|
|
|
|
|
var index = s.entry;
|
|
|
|
|
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
|
|
|
|
int count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
|
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
|
current = PICK_NOT_DONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (count == 0) return PICK_NOT_DONE;
|
|
|
|
|
if (best == null
|
|
|
|
|
|| count < count2
|
|
|
|
|
|| (count == count2 && s.score > bestScore)) {
|
|
|
|
|
@@ -296,36 +268,30 @@ public record SwedishGenerator() {
|
|
|
|
|
if (count <= 1) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (best == null) {
|
|
|
|
|
current = PICK_DONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (best == null) return PICK_DONE;
|
|
|
|
|
var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi);
|
|
|
|
|
var index = best.entry;
|
|
|
|
|
current = CARRIER;
|
|
|
|
|
current.slot = best;
|
|
|
|
|
current.count = index.length;
|
|
|
|
|
current.indices = pattern == X ? null : candidateInfoForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
|
|
|
|
currentSlot = best;
|
|
|
|
|
var index = best.entry;
|
|
|
|
|
currentIndices = pattern == X ? null : candidateInfoForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
boolean backtrack(int depth) {
|
|
|
|
|
if (Thread.currentThread().isInterrupted() || (System.currentTimeMillis() - t0) > 20_000) return false;
|
|
|
|
|
nodes++;
|
|
|
|
|
|
|
|
|
|
chooseMRV();
|
|
|
|
|
var pick = current;
|
|
|
|
|
if (pick == PICK_DONE) return true;
|
|
|
|
|
if (pick.slot == null) {
|
|
|
|
|
int status = chooseMRV();
|
|
|
|
|
if (status == PICK_DONE) return true;
|
|
|
|
|
if (status == PICK_NOT_DONE) {
|
|
|
|
|
backtracks++;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
val info = pick.indices;
|
|
|
|
|
lastMRV = pick.count;
|
|
|
|
|
|
|
|
|
|
val s = pick.slot;
|
|
|
|
|
val inc = Slotinfo.increasing(s.key);
|
|
|
|
|
val slo = s.lo;
|
|
|
|
|
val shi = s.hi;
|
|
|
|
|
val entry = s.entry;
|
|
|
|
|
val info = currentIndices;
|
|
|
|
|
val s = currentSlot;
|
|
|
|
|
val inc = Slotinfo.increasing(s.key);
|
|
|
|
|
val slo = s.lo;
|
|
|
|
|
val shi = s.hi;
|
|
|
|
|
val assign = s.assign;
|
|
|
|
|
val words = s.entry.words;
|
|
|
|
|
long low, top;
|
|
|
|
|
if (info != null && info.length > 0) {
|
|
|
|
|
var idxs = info;
|
|
|
|
|
@@ -333,7 +299,7 @@ public record SwedishGenerator() {
|
|
|
|
|
var tries = Math.min(MAX_TRIES_PER_SLOT, L);
|
|
|
|
|
|
|
|
|
|
for (var t = 0; t < tries; t++) {
|
|
|
|
|
var w = entry.words[idxs[rng.biasedIndexPow3(L - 1)]];
|
|
|
|
|
var w = words[idxs[rng.biasedIndexPow3(L - 1)]];
|
|
|
|
|
var lemIdx = Lemma.unpackIndex(w);
|
|
|
|
|
if (Bit1029.get(used, lemIdx)) continue;
|
|
|
|
|
low = glo;
|
|
|
|
|
@@ -345,9 +311,9 @@ public record SwedishGenerator() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit1029.set(used, lemIdx);
|
|
|
|
|
s.assign.w = w;
|
|
|
|
|
assign.w = w;
|
|
|
|
|
if (backtrack(depth + 1)) return true;
|
|
|
|
|
s.assign.w = X;
|
|
|
|
|
assign.w = X;
|
|
|
|
|
Bit1029.clear(used, lemIdx);
|
|
|
|
|
glo = low;
|
|
|
|
|
ghi = top;
|
|
|
|
|
@@ -356,11 +322,11 @@ public record SwedishGenerator() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var N = entry.words.length;
|
|
|
|
|
var N = words.length;
|
|
|
|
|
|
|
|
|
|
var tries = Math.min(MAX_TRIES_PER_SLOT, N);
|
|
|
|
|
for (var t = 0; t < tries; t++) {
|
|
|
|
|
var w = entry.words[rng.biasedIndexPow3(N - 1)];
|
|
|
|
|
var w = words[rng.biasedIndexPow3(N - 1)];
|
|
|
|
|
var lemIdx = Lemma.unpackIndex(w);
|
|
|
|
|
if (Bit1029.get(used, lemIdx)) continue;
|
|
|
|
|
low = glo;
|
|
|
|
|
@@ -372,9 +338,9 @@ public record SwedishGenerator() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit1029.set(used, lemIdx);
|
|
|
|
|
s.assign.w = w;
|
|
|
|
|
assign.w = w;
|
|
|
|
|
if (backtrack(depth + 1)) return true;
|
|
|
|
|
s.assign.w = X;
|
|
|
|
|
assign.w = X;
|
|
|
|
|
Bit1029.clear(used, lemIdx);
|
|
|
|
|
|
|
|
|
|
glo = low;
|
|
|
|
|
@@ -391,6 +357,7 @@ public record SwedishGenerator() {
|
|
|
|
|
grid.lo = solver.glo;
|
|
|
|
|
grid.hi = solver.ghi;
|
|
|
|
|
|
|
|
|
|
return new FillResult(ok, solver.nodes, solver.backtracks, solver.lastMRV, System.currentTimeMillis() - t0, new FillStats());
|
|
|
|
|
return new FillResult(ok, solver.nodes, solver.backtracks, solver.currentSlot == null ? 0 : solver.currentSlot.entry.length, System.currentTimeMillis() - t0,
|
|
|
|
|
new FillStats());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|