introduce bitloops

This commit is contained in:
mike
2026-01-17 02:43:32 +01:00
parent a2134f0dce
commit 57be64c37e
2 changed files with 77 additions and 72 deletions

View File

@@ -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 record Slot(int key, long lo, long hi, DictEntry entry) {
static final int BIT_FOR_DIR = 2; static final int BIT_FOR_DIR = 2;
@@ -725,11 +728,39 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
} }
return best.grid; return best.grid;
} }
static long patternForSlot2(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) {
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;
if (((lo & glo) | (hi & ghi)) == X) { long p = 0;
return 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; long p = 0;
if (Slot.increasing(key)) { if (Slot.increasing(key)) {
for (long b = lo & glo; b != X; b &= b - 1) { 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) { static int[] candidateInfoForPattern(long[] res, long pattern, long[][] posBitsets, int numLongs) {
boolean first = true; System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs);
for (long p = pattern >>> 8; p != X; p >>>= 8) {
for (long p = pattern; p != X; ) { long[] bs = posBitsets[(int) (p & 0xFF) - 1];
int combined = (int) (p & 0xFF); for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
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);
}
} }
int count = 0; int count = 0;
for (int k = 0; k < numLongs; k++) count += bitCount(res[k]); for (int k = 0; k < numLongs; k++) count += bitCount(res[k]);
int[] indices = new int[count]; int[] indices = new int[count];
int ki = 0; for (int k = 0, ki = 0; k < numLongs; k++) {
for (int k = 0; k < numLongs; k++) {
long w = res[k]; long w = res[k];
while (w != X) { while (w != X) {
int t = numberOfTrailingZeros(w); indices[ki++] = (k << 6) | numberOfTrailingZeros(w);
indices[ki++] = (k << 6) | t;
w &= w - 1; 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) { static int candidateCountForPattern(final long[] res, final long pattern, final long[][] posBitsets, final int numLongs) {
boolean first = true; System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs);
for (long p = pattern >>> 8; p != X; p >>>= 8) {
for (long p = pattern; p != X; ) { long[] bs = posBitsets[(int) (p & 0xFF) - 1];
int combined = (int) (p & 0xFF); for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
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);
}
} }
int count = 0; int count = 0;
@@ -888,21 +893,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
for (int i = 0; i < slots.length; i++) { for (int i = 0; i < slots.length; i++) {
var slot = slots[i]; var slot = slots[i];
slotScores[i] = slotScore(count, slot.lo, slot.hi); 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; return slotInfo;
} }
public static FillResult fillMask(final Rng rng, final Slotinfo[] slots, public static FillResult fillMask(final Rng rng, final Slotinfo[] slots,
final Grid grid, final Grid grid,
final boolean multiThreaded) { final boolean multiThreaded) {
val NO_LOG = (!Main.VERBOSE || multiThreaded); val NO_LOG = (!Main.VERBOSE || multiThreaded);
val used = new long[2048]; val used = new long[2048];
val assigned = new long[CLUE_INDEX_MAX_SIZE]; val bitset = new long[2500];
val bitset = new long[2500]; val g = grid.g;
val g = grid.g; val TOTAL = slots.length;
val TOTAL = slots.length; val t0 = System.currentTimeMillis();
val t0 = System.currentTimeMillis(); val CARRIER = new Pick(null, null, 0);
val CARRIER = new Pick(null, null, 0);
class Solver { class Solver {
long nodes; long nodes;
@@ -915,8 +919,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
if ((now - lastLog) < LOG_EVERY_MS) return; if ((now - lastLog) < LOG_EVERY_MS) return;
lastLog = (now); lastLog = (now);
var done = 0; var done = 0;
for (var lemma : assigned) { for (var lemma : slots) {
if (lemma != X) done++; if (lemma.assign.w != X) done++;
} }
var pct = (TOTAL == 0) ? 100 : (int) Math.floor((done / (double) TOTAL) * 100); 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)); 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; return true;
} }
void chooseMRV() { void chooseMRV() {
Slotinfo best = null; SwedishGenerator.Slotinfo best = null;
for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) { for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) {
var s = slots[i]; var s = slots[i];
if (assigned[s.key] != X) continue; if (s.assign.w != X) continue;
var pattern = patternForSlot(glo, ghi, g, s.key, s.lo, s.hi); var pattern = patternForSlot2(glo, ghi, g, s.key, s.lo, s.hi);
var index = s.entry; var index = s.entry;
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong); 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; current = PICK_DONE;
return; 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; var index = best.entry;
current = CARRIER; current = CARRIER;
current.slot = best; current.slot = best;
@@ -1032,21 +1036,19 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
for (var t = 0; t < tries; t++) { for (var t = 0; t < tries; t++) {
var r = rng.nextFloat(); var r = rng.nextFloat();
//int idxInArray = rng.biasedIndexPow3(L - 1); //int idxInArray = rng.biasedIndexPow3(L - 1);
int idxInArray = (int) (r * r * r * (L - 1)); var w = entry.words[idxs[(int) (r * r * r * (L - 1))]];
var idx = idxs[idxInArray]; var lemIdx = Lemma.unpackIndex(w);
var w = entry.words[idx];
var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue; if (Bit1029.get(used, lemIdx)) continue;
low = glo; low = glo;
top = ghi; top = ghi;
if (!placeWord(k, slo, shi, w)) continue; if (!placeWord(k, slo, shi, w)) continue;
Bit1029.set(used, lemIdx); Bit1029.set(used, lemIdx);
assigned[k] = w; //assigned[k] = w;
s.assign.w = w;
if (backtrack(depth + 1)) return true; if (backtrack(depth + 1)) return true;
s.assign.w = X;
assigned[k] = X; //assigned[k] = X;
Bit1029.clear(used, lemIdx); Bit1029.clear(used, lemIdx);
glo = low; glo = low;
ghi = top; ghi = top;
@@ -1059,21 +1061,21 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
var tries = Math.min(MAX_TRIES_PER_SLOT, N); var tries = Math.min(MAX_TRIES_PER_SLOT, N);
for (var t = 0; t < tries; t++) { for (var t = 0; t < tries; t++) {
double r = rng.nextFloat(); double r = rng.nextFloat();
int idxInArray = (int) (r * r * r * (N - 1)); var w = entry.words[(int) (r * r * r * (N - 1))];
var w = entry.words[idxInArray]; var lemIdx = Lemma.unpackIndex(w);
var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue; if (Bit1029.get(used, lemIdx)) continue;
low = glo; low = glo;
top = ghi; top = ghi;
if (!placeWord(k, slo, shi, w)) continue; if (!placeWord(k, slo, shi, w)) continue;
Bit1029.set(used, lemIdx); Bit1029.set(used, lemIdx);
assigned[k] = w; s.assign.w = w;
//assigned[k] = w;
if (backtrack(depth + 1)) return true; if (backtrack(depth + 1)) return true;
s.assign.w = X;
assigned[k] = X; //assigned[k] = X;
Bit1029.clear(used, lemIdx); Bit1029.clear(used, lemIdx);
glo = low; glo = low;
ghi = top; ghi = top;
@@ -1091,6 +1093,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
// final progress line // final progress line
grid.lo = solver.glo; grid.lo = solver.glo;
grid.hi = solver.ghi; 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, var res = new FillResult(ok, new Gridded(grid), assigned,
new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV)); new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
if (!multiThreaded) { if (!multiThreaded) {

View File

@@ -2,6 +2,7 @@ package puzzle;
import lombok.val; import lombok.val;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import puzzle.Export.ClueAt; import puzzle.Export.ClueAt;
import puzzle.Export.Clued; import puzzle.Export.Clued;