introduce bitloops
This commit is contained in:
@@ -335,10 +335,13 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
}
|
||||
|
||||
static record Slotinfo(int key, long lo, long hi, int score, DictEntry entry) {
|
||||
|
||||
static class Assign {
|
||||
|
||||
long w;
|
||||
}
|
||||
|
||||
static record Slotinfo(int key, long lo, long hi, int score, Assign assign, DictEntry entry) { }
|
||||
|
||||
static record Slot(int key, long lo, long hi, DictEntry entry) {
|
||||
|
||||
static final int BIT_FOR_DIR = 2;
|
||||
@@ -725,11 +728,39 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
return best.grid;
|
||||
}
|
||||
|
||||
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 0;
|
||||
static long patternForSlot2(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 0;
|
||||
long p = 0;
|
||||
int n = 0;
|
||||
if (Slot.increasing(key)) {
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = bitCount(lo & ((1L << idx) - 1));
|
||||
p |= ((long) (i * 26 + g[idx])) << (n++ << 3);
|
||||
}
|
||||
int offset = bitCount(lo);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = offset + bitCount(hi & ((1L << idx) - 1));
|
||||
p |= ((long) (i * 26 + g[64 | idx])) << (n++ << 3);
|
||||
}
|
||||
} else {
|
||||
int offset = bitCount(hi);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
|
||||
p |= ((long) (i * 26 + g[64 | idx])) << (n++ << 3);
|
||||
}
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = offset + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
|
||||
p |= ((long) (i * 26 + g[idx])) << (n++ << 3);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
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 0;
|
||||
long p = 0;
|
||||
if (Slot.increasing(key)) {
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
@@ -819,34 +850,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
|
||||
static int[] candidateInfoForPattern(long[] res, long pattern, long[][] posBitsets, int numLongs) {
|
||||
boolean first = true;
|
||||
|
||||
for (long p = pattern; p != X; ) {
|
||||
int combined = (int) (p & 0xFF);
|
||||
if (combined != X) {
|
||||
long[] bs = posBitsets[combined - 1];
|
||||
if (first) {
|
||||
System.arraycopy(bs, 0, res, 0, numLongs);
|
||||
first = false;
|
||||
} else {
|
||||
for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
|
||||
}
|
||||
p >>>= 8;
|
||||
} else {
|
||||
p >>>= (numberOfTrailingZeros(p) & ~7);
|
||||
}
|
||||
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];
|
||||
int ki = 0;
|
||||
for (int k = 0; k < numLongs; k++) {
|
||||
for (int k = 0, ki = 0; k < numLongs; k++) {
|
||||
long w = res[k];
|
||||
while (w != X) {
|
||||
int t = numberOfTrailingZeros(w);
|
||||
indices[ki++] = (k << 6) | t;
|
||||
indices[ki++] = (k << 6) | numberOfTrailingZeros(w);
|
||||
w &= w - 1;
|
||||
}
|
||||
}
|
||||
@@ -855,22 +872,10 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
|
||||
static int candidateCountForPattern(final long[] res, final long pattern, final long[][] posBitsets, final int numLongs) {
|
||||
boolean first = true;
|
||||
|
||||
for (long p = pattern; p != X; ) {
|
||||
int combined = (int) (p & 0xFF);
|
||||
if (combined != X) {
|
||||
long[] bs = posBitsets[combined - 1];
|
||||
if (first) {
|
||||
System.arraycopy(bs, 0, res, 0, numLongs);
|
||||
first = false;
|
||||
} else {
|
||||
for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
|
||||
}
|
||||
p >>>= 8;
|
||||
} else {
|
||||
p >>>= (numberOfTrailingZeros(p) & ~7);
|
||||
}
|
||||
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;
|
||||
@@ -888,21 +893,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
var slot = slots[i];
|
||||
slotScores[i] = slotScore(count, slot.lo, slot.hi);
|
||||
slotInfo[i] = new Slotinfo(slot.key, slot.lo, slot.hi, slotScores[i], slot.entry);
|
||||
slotInfo[i] = new Slotinfo(slot.key, slot.lo, slot.hi, slotScores[i], new Assign(), slot.entry);
|
||||
}
|
||||
return slotInfo;
|
||||
}
|
||||
public static FillResult fillMask(final Rng rng, final Slotinfo[] slots,
|
||||
final Grid grid,
|
||||
final boolean multiThreaded) {
|
||||
val NO_LOG = (!Main.VERBOSE || multiThreaded);
|
||||
val used = new long[2048];
|
||||
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
||||
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 NO_LOG = (!Main.VERBOSE || multiThreaded);
|
||||
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);
|
||||
class Solver {
|
||||
|
||||
long nodes;
|
||||
@@ -915,8 +919,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
if ((now - lastLog) < LOG_EVERY_MS) return;
|
||||
lastLog = (now);
|
||||
var done = 0;
|
||||
for (var lemma : assigned) {
|
||||
if (lemma != X) done++;
|
||||
for (var lemma : slots) {
|
||||
if (lemma.assign.w != X) done++;
|
||||
}
|
||||
var pct = (TOTAL == 0) ? 100 : (int) Math.floor((done / (double) TOTAL) * 100);
|
||||
var filled = Math.min(BAR_LEN, (int) Math.floor((pct / 100.0) * BAR_LEN));
|
||||
@@ -964,11 +968,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
return true;
|
||||
}
|
||||
void chooseMRV() {
|
||||
Slotinfo best = null;
|
||||
SwedishGenerator.Slotinfo best = null;
|
||||
for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) {
|
||||
var s = slots[i];
|
||||
if (assigned[s.key] != X) continue;
|
||||
var pattern = patternForSlot(glo, ghi, g, s.key, s.lo, s.hi);
|
||||
if (s.assign.w != X) continue;
|
||||
var pattern = patternForSlot2(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);
|
||||
|
||||
@@ -990,7 +994,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
current = PICK_DONE;
|
||||
return;
|
||||
}
|
||||
var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi);
|
||||
var pattern = patternForSlot2(glo, ghi, g, best.key, best.lo, best.hi);
|
||||
var index = best.entry;
|
||||
current = CARRIER;
|
||||
current.slot = best;
|
||||
@@ -1032,21 +1036,19 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
for (var t = 0; t < tries; t++) {
|
||||
var r = rng.nextFloat();
|
||||
//int idxInArray = rng.biasedIndexPow3(L - 1);
|
||||
int idxInArray = (int) (r * r * r * (L - 1));
|
||||
var idx = idxs[idxInArray];
|
||||
var w = entry.words[idx];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
var w = entry.words[idxs[(int) (r * r * r * (L - 1))]];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
if (Bit1029.get(used, lemIdx)) continue;
|
||||
low = glo;
|
||||
top = ghi;
|
||||
if (!placeWord(k, slo, shi, w)) continue;
|
||||
|
||||
Bit1029.set(used, lemIdx);
|
||||
assigned[k] = w;
|
||||
|
||||
//assigned[k] = w;
|
||||
s.assign.w = w;
|
||||
if (backtrack(depth + 1)) return true;
|
||||
|
||||
assigned[k] = X;
|
||||
s.assign.w = X;
|
||||
//assigned[k] = X;
|
||||
Bit1029.clear(used, lemIdx);
|
||||
glo = low;
|
||||
ghi = top;
|
||||
@@ -1059,21 +1061,21 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
var tries = Math.min(MAX_TRIES_PER_SLOT, N);
|
||||
for (var t = 0; t < tries; t++) {
|
||||
double r = rng.nextFloat();
|
||||
int idxInArray = (int) (r * r * r * (N - 1));
|
||||
var w = entry.words[idxInArray];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
double r = rng.nextFloat();
|
||||
var w = entry.words[(int) (r * r * r * (N - 1))];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
if (Bit1029.get(used, lemIdx)) continue;
|
||||
low = glo;
|
||||
top = ghi;
|
||||
if (!placeWord(k, slo, shi, w)) continue;
|
||||
|
||||
Bit1029.set(used, lemIdx);
|
||||
assigned[k] = w;
|
||||
s.assign.w = w;
|
||||
//assigned[k] = w;
|
||||
|
||||
if (backtrack(depth + 1)) return true;
|
||||
|
||||
assigned[k] = X;
|
||||
s.assign.w = X;
|
||||
//assigned[k] = X;
|
||||
Bit1029.clear(used, lemIdx);
|
||||
glo = low;
|
||||
ghi = top;
|
||||
@@ -1091,6 +1093,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
// final progress line
|
||||
grid.lo = solver.glo;
|
||||
grid.hi = solver.ghi;
|
||||
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
||||
Arrays.stream(slots).forEach(s -> assigned[s.key] = s.assign.w);
|
||||
var res = new FillResult(ok, new Gridded(grid), assigned,
|
||||
new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
|
||||
if (!multiThreaded) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package puzzle;
|
||||
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import puzzle.Export.ClueAt;
|
||||
import puzzle.Export.Clued;
|
||||
|
||||
Reference in New Issue
Block a user