redo
This commit is contained in:
@@ -3,6 +3,8 @@ package puzzle;
|
||||
import anno.ConstGen;
|
||||
import anno.GenerateNeighbor;
|
||||
import anno.GenerateNeighbors;
|
||||
import anno.GenerateShapedCopies;
|
||||
import anno.Shaped;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.val;
|
||||
@@ -33,21 +35,21 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
@GenerateNeighbor(C = 9, R = 8, packageName = "precomp", className = "Neighbors9x8", MIN_LEN = 2),
|
||||
@GenerateNeighbor(C = 4, R = 3, packageName = "precomp", className = "Neighbors4x3", MIN_LEN = 2)
|
||||
})
|
||||
|
||||
/*@GenerateShapedCopies(
|
||||
className = "SwedishGeneratorX",
|
||||
shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" }
|
||||
)*/
|
||||
public record SwedishGenerator() {
|
||||
|
||||
public static final long X = 0L;
|
||||
public static final int SIZE = Neighbors9x8.SIZE;
|
||||
public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT;
|
||||
public static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;
|
||||
public static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;
|
||||
public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT;
|
||||
public static final long X = 0L;
|
||||
@Shaped private static final int SIZE = Neighbors9x8.SIZE;
|
||||
@Shaped private static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;
|
||||
@Shaped private static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;
|
||||
|
||||
public static boolean isLo(int n) { return (n & 64) == 0; }
|
||||
interface Bit1029 {
|
||||
|
||||
static long[] bit1029() { return new long[2048]; }
|
||||
private static int wordIndex(int bitIndex) { return bitIndex >> 6; }
|
||||
static boolean get(long[] bits, int bitIndex) { return (bits[wordIndex(bitIndex)] & 1L << bitIndex) != X; }
|
||||
static void set(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; }
|
||||
@@ -55,12 +57,11 @@ public record SwedishGenerator() {
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
public record Dict(DictEntry[] index, int length) { }
|
||||
public record Dict(DictEntry[] index,DictEntry[] reversed, int length) { public Dict(DictEntry[] index,int length){this(index,index,length);} }
|
||||
public record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
|
||||
@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 record FillResult(boolean ok, long nodes, long backtracks, int lastMRV, long elapsed, FillStats stats) { }
|
||||
public record FillResult(boolean ok, long nodes, long backtracks, int lastMRV, long elapsed ) { }
|
||||
//@formatter:on
|
||||
|
||||
public static final class Rng {
|
||||
@@ -98,15 +99,15 @@ public record SwedishGenerator() {
|
||||
static long pack(long w, int shardIndex) { return w | (((long) shardIndex) << 43) | ((long) length0(w)) << 40; }
|
||||
static long packShiftIn(byte[] b) {
|
||||
long w = 0;
|
||||
for (int i = b.length - 1; i >= 0; i--) w = (w << 5) | ((long) b[i] & 31);
|
||||
for (var i = b.length - 1; i >= 0; i--) w = (w << 5) | ((long) b[i] & 31);
|
||||
return w;
|
||||
}
|
||||
static long from(String word) { return packShiftIn(word.getBytes(US_ASCII)) | ((long) (word.length() - 1) << 40); }
|
||||
static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111L); }
|
||||
static int length0(long word) { return ((63 - numberOfLeadingZeros(word & LETTER_MASK)) / 5); }
|
||||
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);
|
||||
var bi = 0;
|
||||
for (var 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); }
|
||||
@@ -132,70 +133,45 @@ public record SwedishGenerator() {
|
||||
}
|
||||
}
|
||||
|
||||
public static long patternForSlot(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) {
|
||||
if (((lo & glo) | (hi & ghi)) == X) return X;
|
||||
public static long patternForSlot(final long glo, final long ghi, final byte[] g, final long lo, final long hi) {
|
||||
if (((lo & glo) == X) && (hi & ghi) == X) return X;
|
||||
long p = 0;
|
||||
int n = 0, offset, idx;
|
||||
if (Slotinfo.increasing(key)) {
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
idx = numberOfTrailingZeros(b);
|
||||
p |= ((long) (bitCount(lo & ((1L << idx) - 1)) * 26 + g[idx])) << (n++ << 3);
|
||||
}
|
||||
offset = bitCount(lo);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
idx = numberOfTrailingZeros(b);
|
||||
p |= ((long) ((offset + bitCount(hi & ((1L << idx) - 1))) * 26 + g[64 | idx])) << (n++ << 3);
|
||||
}
|
||||
} else {
|
||||
offset = bitCount(hi);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
idx = numberOfTrailingZeros(b);
|
||||
p |= ((long) (bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))) * 26 + g[64 | idx])) << (n++ << 3);
|
||||
}
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
idx = numberOfTrailingZeros(b);
|
||||
p |= ((long) ((offset + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)))) * 26 + g[idx])) << (n++ << 3);
|
||||
}
|
||||
for (var b = lo & glo; b != X; b &= b - 1) {
|
||||
idx = numberOfTrailingZeros(b);
|
||||
p |= ((long) (bitCount(lo & ((1L << idx) - 1)) * 26 + g[idx])) << (n++ << 3);
|
||||
}
|
||||
offset = bitCount(lo);
|
||||
for (var b = hi & ghi; b != X; b &= b - 1) {
|
||||
idx = numberOfTrailingZeros(b);
|
||||
p |= ((long) ((offset + bitCount(hi & ((1L << idx) - 1))) * 26 + g[64 | idx])) << (n++ << 3);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/// pattern cannot be X
|
||||
public static int[] candidateInfoForPattern(long[] res, long pattern, long[][] posBitsets, int numLongs) {
|
||||
System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs);
|
||||
for (long p = pattern >>> 8; p != X; p >>>= 8) {
|
||||
long[] bs = posBitsets[(int) (p & 0xFF) - 1];
|
||||
for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int k = 0; k < numLongs; k++) count += bitCount(res[k]);
|
||||
|
||||
int[] indices = new int[count];
|
||||
for (int k = 0, ki = 0; k < numLongs; k++) {
|
||||
for (long w = res[k]; w != X; w &= w - 1) indices[ki++] = (k << 6) | numberOfTrailingZeros(w);
|
||||
}
|
||||
|
||||
var indices = new int[candidateCountForPattern(res, pattern, posBitsets, numLongs)];
|
||||
for (int k = 0, ki = 0; k < numLongs; k++) for (var w = res[k]; w != X; w &= w - 1) indices[ki++] = (k << 6) | numberOfTrailingZeros(w);
|
||||
return indices;
|
||||
}
|
||||
/// pattern cannot be X
|
||||
public static int candidateCountForPattern(final long[] res, final long pattern, final long[][] posBitsets, final int numLongs) {
|
||||
System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs);
|
||||
for (long p = pattern >>> 8; p != X; p >>>= 8) {
|
||||
long[] bs = posBitsets[(int) (p & 0xFF) - 1];
|
||||
for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
|
||||
public static int candidateCountForPattern(final long[] res, final long pattern, final long[][] pos, final int num) {
|
||||
System.arraycopy(pos[(int) (pattern & 0xFF) - 1], 0, res, 0, num);
|
||||
for (var p = pattern >>> 8; p != X; p >>>= 8) {
|
||||
var bs = pos[(int) (p & 0xFF) - 1];
|
||||
for (var k = 0; k < num; k++) res[k] &= bs[k];
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int k = 0; k < numLongs; k++) count += bitCount(res[k]);
|
||||
var count = 0;
|
||||
for (var k = 0; k < num; k++) count += bitCount(res[k]);
|
||||
return count;
|
||||
}
|
||||
|
||||
public static FillResult fillMask(final Rng rng, final Slotinfo[] slots,
|
||||
final Grid grid) {
|
||||
final long lo, final long hi, final byte[] g) {
|
||||
val used = new long[2048];
|
||||
val bitset = new long[2500];
|
||||
val g = grid.g;
|
||||
val TOTAL = slots.length;
|
||||
val t0 = System.currentTimeMillis();
|
||||
class Solver {
|
||||
@@ -203,82 +179,64 @@ public record SwedishGenerator() {
|
||||
static final int PICK_NOT_DONE = -1;
|
||||
static final int PICK_DONE = 0;
|
||||
long nodes;
|
||||
long backtracks;
|
||||
long glo = grid.lo, ghi = grid.hi;
|
||||
Slotinfo currentSlot;
|
||||
int[] currentIndices;
|
||||
boolean placeWordDec(final long lo, final long hi, final long w) {
|
||||
long tracks;
|
||||
long glo = lo, ghi = hi;
|
||||
Slotinfo slot;
|
||||
int[] indices;
|
||||
boolean place(final long lo, final long hi, final long w) {
|
||||
int idx;
|
||||
int bcHi = bitCount(hi);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1)
|
||||
if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
for (long b = lo & glo; b != X; b &= b - 1)
|
||||
if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
for (var b = lo & glo; b != X; b &= b - 1) if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return true;
|
||||
var bcLo = bitCount(lo);
|
||||
for (var b = hi & ghi; b != X; b &= b - 1) if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)))) return true;
|
||||
|
||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||
if ((maskLo | maskHi) != X) {
|
||||
for (long b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
for (long b = maskLo; b != X; b &= b - 1) g[idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
for (var b = maskLo; b != X; b &= b - 1) g[idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)));
|
||||
for (var b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)));
|
||||
glo |= maskLo;
|
||||
ghi |= maskHi;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
boolean placeWordInc(final long lo, final long hi, final long w) {
|
||||
int idx;
|
||||
for (long b = lo & glo; b != X; b &= b - 1) if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return false;
|
||||
int bcLo = bitCount(lo);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)))) return false;
|
||||
|
||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||
if ((maskLo | maskHi) != X) {
|
||||
for (long b = maskLo; b != X; b &= b - 1) g[idx = idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)));
|
||||
for (long b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)));
|
||||
glo |= maskLo;
|
||||
ghi |= maskHi;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
int chooseMRV() {
|
||||
Slotinfo best = null;
|
||||
int count2 = -1, bestScore = -1;
|
||||
Slotinfo best = null;
|
||||
int max = -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 pattern = patternForSlot(glo, ghi, g, s.lo, s.hi);
|
||||
var index = s.entry;
|
||||
int count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
||||
var count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
||||
|
||||
if (count == 0) return PICK_NOT_DONE;
|
||||
if (best == null
|
||||
|| count < count2
|
||||
|| (count == count2 && s.score > bestScore)) {
|
||||
|| count < max
|
||||
|| (count == max && s.score > bestScore)) {
|
||||
best = s;
|
||||
bestScore = s.score;
|
||||
count2 = count;
|
||||
max = count;
|
||||
if (count <= 1) break;
|
||||
}
|
||||
}
|
||||
if (best == null) return PICK_DONE;
|
||||
var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi);
|
||||
currentSlot = best;
|
||||
var pattern = patternForSlot(glo, ghi, g, best.lo, best.hi);
|
||||
slot = best;
|
||||
var index = best.entry;
|
||||
currentIndices = pattern == X ? null : candidateInfoForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
||||
indices = 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++;
|
||||
|
||||
int status = chooseMRV();
|
||||
var status = chooseMRV();
|
||||
if (status == PICK_DONE) return true;
|
||||
if (status == PICK_NOT_DONE) {
|
||||
backtracks++;
|
||||
tracks++;
|
||||
return false;
|
||||
}
|
||||
val info = currentIndices;
|
||||
val s = currentSlot;
|
||||
val inc = Slotinfo.increasing(s.key);
|
||||
val info = indices;
|
||||
val s = slot;
|
||||
val slo = s.lo;
|
||||
val shi = s.hi;
|
||||
val assign = s.assign;
|
||||
@@ -294,11 +252,7 @@ public record SwedishGenerator() {
|
||||
if (Bit1029.get(used, lemIdx)) continue;
|
||||
low = glo;
|
||||
top = ghi;
|
||||
if (inc) {
|
||||
if (!placeWordInc(slo, shi, w)) continue;
|
||||
} else {
|
||||
if (!placeWordDec(slo, shi, w)) continue;
|
||||
}
|
||||
if (place(slo, shi, w)) continue;
|
||||
|
||||
Bit1029.set(used, lemIdx);
|
||||
assign.w = w;
|
||||
@@ -308,45 +262,36 @@ public record SwedishGenerator() {
|
||||
glo = low;
|
||||
ghi = top;
|
||||
}
|
||||
backtracks++;
|
||||
tracks++;
|
||||
return false;
|
||||
}
|
||||
|
||||
var N = words.length;
|
||||
|
||||
for (var t = 0; t < s.minL; t++) {
|
||||
var w = words[rng.biasedIndexPow3(N - 1)];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
if (Bit1029.get(used, lemIdx)) continue;
|
||||
var w = words[rng.biasedIndexPow3(N - 1)];
|
||||
var lem = Lemma.unpackIndex(w);
|
||||
if (Bit1029.get(used, lem)) continue;
|
||||
low = glo;
|
||||
top = ghi;
|
||||
if (inc) {
|
||||
if (!placeWordInc(slo, shi, w)) continue;
|
||||
} else {
|
||||
if (!placeWordDec(slo, shi, w)) continue;
|
||||
}
|
||||
if (place(slo, shi, w)) continue;
|
||||
|
||||
Bit1029.set(used, lemIdx);
|
||||
Bit1029.set(used, lem);
|
||||
assign.w = w;
|
||||
if (backtrack(depth + 1)) return true;
|
||||
assign.w = X;
|
||||
Bit1029.clear(used, lemIdx);
|
||||
Bit1029.clear(used, lem);
|
||||
|
||||
glo = low;
|
||||
ghi = top;
|
||||
}
|
||||
|
||||
backtracks++;
|
||||
tracks++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var solver = new Solver();
|
||||
var ok = solver.backtrack(0);
|
||||
grid.lo = solver.glo;
|
||||
grid.hi = solver.ghi;
|
||||
|
||||
return new FillResult(ok, solver.nodes, solver.backtracks, solver.currentSlot == null ? 0 : solver.currentSlot.entry.length, System.currentTimeMillis() - t0,
|
||||
new FillStats());
|
||||
return new FillResult(ok, solver.nodes, solver.tracks, solver.slot == null ? 0 : solver.slot.entry.length, System.currentTimeMillis() - t0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user