introduce bitloops

This commit is contained in:
mike
2026-01-17 01:15:03 +01:00
parent 60b7509bf6
commit 4585c1f2eb
3 changed files with 146 additions and 120 deletions

View File

@@ -388,8 +388,8 @@ public class Main {
var swe = new SwedishGenerator(rng, new int[STACK_SIZE], Clues.createEmpty());
var mask = swe.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
if (mask == null) return null;
var filled = fillMask(rng, extractSlots(mask, dict.index()), mask.toGrid());
val multiThreaded = Thread.currentThread().getName().contains("pool");
var filled = fillMask(rng, extractSlots(mask, dict.index()), mask.toGrid(), multiThreaded);
TOTAL_NODES.addAndGet(filled.stats().nodes);
TOTAL_BACKTRACKS.addAndGet(filled.stats().backtracks);

View File

@@ -22,6 +22,8 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
import java.util.stream.IntStream;
import static java.lang.Long.*;
import static java.lang.Long.numberOfTrailingZeros;
import static java.nio.charset.StandardCharsets.US_ASCII;
/**
@@ -142,8 +144,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
stats.simplicity = k == 0 ? 0 : stats.simplicity / k;
}
}
public int wordCount() {
int k = 0;
public int wordCount(int k) {
for (var n = 1; n < clueMap.length; n++) if (clueMap[n] != X) k++;
return k;
}
@@ -220,23 +221,23 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
public boolean notClue(long index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
public boolean notClue(int index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
public int clueCount() { return Long.bitCount(lo) + Long.bitCount(hi); }
public int clueCount() { return bitCount(lo) + bitCount(hi); }
public double similarity(Clues b) {
long matchLo = (~(lo ^ b.lo)) & (~lo | (~(vlo ^ b.vlo) & ~(rlo ^ b.rlo)));
long matchHi = (~(hi ^ b.hi)) & (~hi | (~(vhi ^ b.vhi) & ~(rhi ^ b.rhi)));
return (Long.bitCount(matchLo & MASK_LO) + Long.bitCount(matchHi & MASK_HI)) / SIZED;
return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED;
}
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
public void forEachSlot(SlotVisitor visitor) {
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 1));
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 0));
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 2));
for (var l = lo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 3));
for (var h = hi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | Long.numberOfTrailingZeros(h), 1));
for (var h = hi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | Long.numberOfTrailingZeros(h), 0));
for (var h = hi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | Long.numberOfTrailingZeros(h)), 2));
for (var h = hi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | Long.numberOfTrailingZeros(h)), 3));
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1));
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0));
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 2));
for (var l = lo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 3));
for (var h = hi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 1));
for (var h = hi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 0));
for (var h = hi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 2));
for (var h = hi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 3));
}
public Clues from(Clues best) {
lo = best.lo;
@@ -275,7 +276,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111); }
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
static int simpel(long w) { return CsvIndexService.simpel(unpackIndex(w)); }
static int length(long word) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
static int length(long word) { return ((63 - numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
static ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[MAX_WORD_LENGTH]);
public static String asWord(long word) {
val len = Lemma.length(word);
@@ -338,7 +339,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
static final int BIT_FOR_DIR = 2;
static Slot from(int key, long lo, long hi, DictEntry entry) { return new Slot(key, lo, hi, entry); }
public static int length(long lo, long hi) { return Long.bitCount(lo) + Long.bitCount(hi); }
public static int length(long lo, long hi) { return bitCount(lo) + bitCount(hi); }
public static int clueIndex(int key) { return key >>> BIT_FOR_DIR; }
public static int dir(int key) { return key & 3; }
public static boolean increasing(int dir) { return (dir & 2) == 0; }
@@ -357,12 +358,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
long hitsHi = rayHi & c.hi;
if (hitsHi != X) {
int msb = 63 - Long.numberOfLeadingZeros(hitsHi);
int msb = 63 - numberOfLeadingZeros(hitsHi);
long stop = 1L << msb;
rayHi &= ~((stop << 1) - 1); // keep bits > stop
rayLo = 0; // lo indices are below stop
} else if (hitsLo != X) {
int msb = 63 - Long.numberOfLeadingZeros(hitsLo);
int msb = 63 - numberOfLeadingZeros(hitsLo);
long stop = 1L << msb;
rayLo &= ~((stop << 1) - 1);
}
@@ -376,11 +377,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
long hitsHi = rayHi & c.hi;
if (hitsLo != X) {
long stop = 1L << Long.numberOfTrailingZeros(hitsLo);
long stop = 1L << numberOfTrailingZeros(hitsLo);
rayLo &= (stop - 1);
rayHi = 0; // any hi is beyond the stop
} else if (hitsHi != X) {
long stop = 1L << Long.numberOfTrailingZeros(hitsHi);
long stop = 1L << numberOfTrailingZeros(hitsHi);
// keep all lo (lo indices are < any hi index), but cut hi below stop
rayHi &= (stop - 1);
}
@@ -405,7 +406,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
for (long bits = lo_cl; bits != X; bits &= bits - 1) {
long lsb = bits & -bits;
int clueIdx = Long.numberOfTrailingZeros(lsb);
int clueIdx = numberOfTrailingZeros(lsb);
int v = (grid.vlo & lsb) != 0 ? 1 : 0;
int r = (grid.rlo & lsb) != 0 ? 1 : 0;
int key = Slot.packSlotKey(clueIdx, (r << 1) | v);
@@ -413,16 +414,16 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
if (Slot.increasing(key)) {
if (hLo != X) {
rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1);
rLo &= ((1L << numberOfTrailingZeros(hLo)) - 1);
rHi = 0;
} else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); }
} else if (hHi != X) { rHi &= ((1L << numberOfTrailingZeros(hHi)) - 1); }
} else {
if (hHi != X) {
int msb = 63 - Long.numberOfLeadingZeros(hHi);
int msb = 63 - numberOfLeadingZeros(hHi);
rHi &= ~((1L << msb << 1) - 1);
rLo = 0;
} else if (hLo != X) {
int msb = 63 - Long.numberOfLeadingZeros(hLo);
int msb = 63 - numberOfLeadingZeros(hLo);
rLo &= ~((1L << msb << 1) - 1);
}
}
@@ -435,14 +436,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
cVLo |= rLo;
cVHi |= rHi;
}
if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000;
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
} else {
penalty += 25000;
}
}
for (long bits = hi_cl; bits != X; bits &= bits - 1) {
long lsb = bits & -bits;
int clueIdx = Long.numberOfTrailingZeros(lsb);
int clueIdx = numberOfTrailingZeros(lsb);
int v = (grid.vhi & lsb) != 0 ? 1 : 0;
int r = (grid.rhi & lsb) != 0 ? 1 : 0;
int key = Slot.packSlotKey(64 | clueIdx, (r << 1) | v);
@@ -450,16 +451,16 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
if (Slot.increasing(key)) {
if (hLo != X) {
rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1);
rLo &= ((1L << numberOfTrailingZeros(hLo)) - 1);
rHi = 0;
} else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); }
} else if (hHi != X) { rHi &= ((1L << numberOfTrailingZeros(hHi)) - 1); }
} else {
if (hHi != X) {
int msb = 63 - Long.numberOfLeadingZeros(hHi);
int msb = 63 - numberOfLeadingZeros(hHi);
rHi &= ~((1L << msb << 1) - 1);
rLo = 0;
} else if (hLo != X) {
int msb = 63 - Long.numberOfLeadingZeros(hLo);
int msb = 63 - numberOfLeadingZeros(hLo);
rLo &= ~((1L << msb << 1) - 1);
}
}
@@ -472,7 +473,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
cVLo |= rLo;
cVHi |= rHi;
}
if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000;
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
} else {
penalty += 25000;
}
@@ -488,7 +489,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
// "unseen clues" in deze helft
for (long bits = clueMask & ~seenMask, nLo, nHi; bits != X; bits &= bits - 1) {
int clueIdx = base | Long.numberOfTrailingZeros(bits);
int clueIdx = base | numberOfTrailingZeros(bits);
// start nieuwe component
size = 0;
@@ -515,7 +516,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
// push lo-neighbors
while (nLo != X) {
long lsb = nLo & -nLo;
int nidx = Long.numberOfTrailingZeros(nLo); // 0..63
int nidx = numberOfTrailingZeros(nLo); // 0..63
seenLo |= lsb;
stack[sp++] = nidx;
@@ -526,7 +527,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
// push hi-neighbors
while (nHi != X) {
long lsb = nHi & -nHi;
int nidx = 64 | Long.numberOfTrailingZeros(nHi); // 64..127
int nidx = 64 | numberOfTrailingZeros(nHi); // 64..127
seenHi |= lsb;
stack[sp++] = nidx;
@@ -540,9 +541,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
}
for (long bits = ~lo_cl; bits != X; bits &= bits - 1) {
int clueIdx = Long.numberOfTrailingZeros(bits);
int clueIdx = numberOfTrailingZeros(bits);
var rci = IT[clueIdx];
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
boolean h = (cHLo & (1L << clueIdx)) != X;
boolean v = (cVLo & (1L << clueIdx)) != X;
if (!h && !v) penalty += 1500;
@@ -550,9 +551,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
else penalty += 600;
}
for (long bits = ~hi_cl & 0xFFL; bits != X; bits &= bits - 1) {
int clueIdx = Long.numberOfTrailingZeros(bits);
int clueIdx = numberOfTrailingZeros(bits);
var rci = IT[64 | clueIdx];
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
boolean h = (cHHi & (1L << clueIdx)) != X;
boolean v = (cVHi & (1L << clueIdx)) != X;
if (!h && !v) penalty += 1500;
@@ -629,14 +630,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
(a.rlo & ~maskLo) | (other.rlo & maskLo),
(a.rhi & ~maskHi) | (other.rhi & maskHi));
for (var l = c.lo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 0);
for (var l = c.lo & ~c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 1);
for (var l = c.lo & c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 2);
for (var l = c.lo & c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 3);
for (var h = c.hi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, Long.numberOfTrailingZeros(h), 0);
for (var h = c.hi & ~c.rhi & c.vhi; h != X; h &= h - 1) clearCluesHi(c, Long.numberOfTrailingZeros(h), 1);
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (Long.numberOfTrailingZeros(h)), 2);
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (Long.numberOfTrailingZeros(h)), 3);
for (var l = c.lo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 0);
for (var l = c.lo & ~c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 1);
for (var l = c.lo & c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 2);
for (var l = c.lo & c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 3);
for (var h = c.hi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, numberOfTrailingZeros(h), 0);
for (var h = c.hi & ~c.rhi & c.vhi; h != X; h &= h - 1) clearCluesHi(c, numberOfTrailingZeros(h), 1);
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (numberOfTrailingZeros(h)), 2);
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (numberOfTrailingZeros(h)), 3);
return c;
}
public static void clearCluesLo(Clues out, int idx, int d) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d)])) out.clearClueLo(~(1L << idx)); }
@@ -728,26 +729,26 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
long p = 0;
if (Slot.increasing(key)) {
for (long b = lo & glo; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int i = Long.bitCount(lo & ((1L << idx) - 1));
int idx = numberOfTrailingZeros(b);
int i = bitCount(lo & ((1L << idx) - 1));
p |= ((long) (i * 26 + g[idx])) << (i << 3);
}
int offset = Long.bitCount(lo);
int offset = bitCount(lo);
for (long b = hi & ghi; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int i = offset + Long.bitCount(hi & ((1L << idx) - 1));
int idx = numberOfTrailingZeros(b);
int i = offset + bitCount(hi & ((1L << idx) - 1));
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
}
} else {
int offset = Long.bitCount(hi);
int offset = bitCount(hi);
for (long b = hi & ghi; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int i = Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
int idx = numberOfTrailingZeros(b);
int i = bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
}
for (long b = lo & glo; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
int i = offset + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
int idx = numberOfTrailingZeros(b);
int i = offset + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
p |= ((long) (i * 26 + g[idx])) << (i << 3);
}
}
@@ -755,56 +756,56 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
}
static int slotScore(byte[] count, long lo, long hi) {
int cross = 0;
for (long b = lo; b != X; b &= b - 1) cross += (count[Long.numberOfTrailingZeros(b)] - 1);
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
for (long b = lo; b != X; b &= b - 1) cross += (count[numberOfTrailingZeros(b)] - 1);
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | numberOfTrailingZeros(b)] - 1);
return cross * 10 + Slot.length(lo, hi);
}
static boolean placeWord(final Grid grid, final byte[] g, final int key, final long lo, final long hi, final long w) {
final long glo = grid.lo, ghi = grid.hi;
if (Slot.increasing(key)) {
for (long b = lo & glo; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
if (g[idx] != Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)))) return false;
int idx = numberOfTrailingZeros(b);
if (g[idx] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return false;
}
int bcLo = Long.bitCount(lo);
int bcLo = bitCount(lo);
for (long b = hi & ghi; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
if (g[64 | idx] != Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)))) return false;
int idx = numberOfTrailingZeros(b);
if (g[64 | idx] != 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) {
int idx = Long.numberOfTrailingZeros(b);
g[idx] = Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)));
int idx = numberOfTrailingZeros(b);
g[idx] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)));
}
for (long b = maskHi; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
g[64 | idx] = Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)));
int idx = numberOfTrailingZeros(b);
g[64 | idx] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)));
}
grid.lo |= maskLo;
grid.hi |= maskHi;
}
} else {
int bcHi = Long.bitCount(hi);
int bcHi = bitCount(hi);
for (long b = hi & ghi; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
if (g[64 | idx] != Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
int idx = numberOfTrailingZeros(b);
if (g[64 | idx] != Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
}
for (long b = lo & glo; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
if (g[idx] != Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
int idx = numberOfTrailingZeros(b);
if (g[idx] != Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
}
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
if ((maskLo | maskHi) != X) {
for (long b = maskHi; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
g[64 | idx] = Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
int idx = numberOfTrailingZeros(b);
g[64 | idx] = Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
}
for (long b = maskLo; b != X; b &= b - 1) {
int idx = Long.numberOfTrailingZeros(b);
g[idx] = Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
int idx = numberOfTrailingZeros(b);
g[idx] = Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
}
grid.lo |= maskLo;
grid.hi |= maskHi;
@@ -828,19 +829,19 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
}
p >>>= 8;
} else {
p >>>= (Long.numberOfTrailingZeros(p) & ~7);
p >>>= (numberOfTrailingZeros(p) & ~7);
}
}
int count = 0;
for (int k = 0; k < numLongs; k++) count += Long.bitCount(res[k]);
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++) {
long w = res[k];
while (w != X) {
int t = Long.numberOfTrailingZeros(w);
int t = numberOfTrailingZeros(w);
indices[ki++] = (k << 6) | t;
w &= w - 1;
}
@@ -864,20 +865,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
}
p >>>= 8;
} else {
p >>>= (Long.numberOfTrailingZeros(p) & ~7);
p >>>= (numberOfTrailingZeros(p) & ~7);
}
}
int count = 0;
for (int k = 0; k < numLongs; k++) count += Long.bitCount(res[k]);
for (int k = 0; k < numLongs; k++) count += bitCount(res[k]);
return count;
}
static void scoreSlots(int[] slotScores, Slot[] slots) {
val count = new byte[SIZE];
for (var s : slots) {
for (long b = s.lo; b != X; b &= b - 1) count[Long.numberOfTrailingZeros(b)]++;
for (long b = s.hi; b != X; b &= b - 1) count[64 | Long.numberOfTrailingZeros(b)]++;
for (long b = s.lo; b != X; b &= b - 1) count[numberOfTrailingZeros(b)]++;
for (long b = s.hi; b != X; b &= b - 1) count[64 | numberOfTrailingZeros(b)]++;
}
for (int i = 0; i < slots.length; i++) {
var slot = slots[i];
@@ -885,14 +886,13 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
}
}
public static FillResult fillMask(Rng rng, Slot[] slots, Grid mask) {
val multiThreaded = Thread.currentThread().getName().contains("pool");
val NO_LOG = (!Main.VERBOSE || multiThreaded);
val grid = mask;
val used = new long[2048];
val assigned = new long[CLUE_INDEX_MAX_SIZE];
val bitset = new long[2500];
val g = grid.g;
public static FillResult fillMask(final Rng rng,final Slot[] slots,final Grid mask, final boolean multiThreaded) {
val NO_LOG = (!Main.VERBOSE || multiThreaded);
val grid = mask;
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 slotScores = new int[TOTAL];
@@ -907,7 +907,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
long nodes;
long backtracks;
int lastMRV;
long lastLog = t0;
long lastLog = t0, glo = grid.lo, ghi = grid.hi;
Pick current = CARRIER;
void renderProgress() {
var now = System.currentTimeMillis();
@@ -930,12 +930,44 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
System.out.print("\r" + Strings.padRight(msg, 120));
System.out.flush();
}
boolean placeWord(final int key, final long lo, final long hi, final long w) {
int idx;
if (Slot.increasing(key)) {
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;
}
} else {
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;
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))));
glo |= maskLo;
ghi |= maskHi;
}
}
return true;
}
void chooseMRV() {
Slot 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(grid.lo, grid.hi, g, s.key, s.lo, s.hi);
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);
@@ -957,7 +989,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
current = PICK_DONE;
return;
}
var pattern = patternForSlot(grid.lo, grid.hi, g, best.key, best.lo, best.hi);
var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi);
var index = best.entry;
current = CARRIER;
current.slot = best;
@@ -1004,9 +1036,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
var w = entry.words[idx];
var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue;
low = grid.lo;
top = grid.hi;
if (!placeWord(grid, g, k, slo, shi, w)) continue;
low = glo;
top = ghi;
if (!placeWord(k, slo, shi, w)) continue;
Bit1029.set(used, lemIdx);
assigned[k] = w;
@@ -1015,8 +1047,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
assigned[k] = X;
Bit1029.clear(used, lemIdx);
grid.lo = low;
grid.hi = top;
glo = low;
ghi = top;
}
backtracks++;
return false;
@@ -1031,9 +1063,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
var w = entry.words[idxInArray];
var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue;
low = grid.lo;
top = grid.hi;
if (!placeWord(grid, g, k, slo, shi, w)) continue;
low = glo;
top = ghi;
if (!placeWord(k, slo, shi, w)) continue;
Bit1029.set(used, lemIdx);
assigned[k] = w;
@@ -1042,8 +1074,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
assigned[k] = X;
Bit1029.clear(used, lemIdx);
grid.lo = low;
grid.hi = top;
glo = low;
ghi = top;
}
backtracks++;
@@ -1056,7 +1088,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
if (!NO_LOG) solver.renderProgress();
var ok = solver.backtrack(0);
// final progress line
grid.lo = solver.glo;
grid.hi = solver.ghi;
var res = new FillResult(ok, new Gridded(grid), assigned,
new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
if (!multiThreaded) {
@@ -1068,7 +1101,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
System.out.println(
String.format(Locale.ROOT,
"[######################] %d/%d slots | nodes=%d | backtracks=%d | mrv=%d | %.1fs",
res.wordCount(), TOTAL, res.nodes(), res.backtracks(), res.lastMRV(), res.seconds()
res.wordCount(0), TOTAL, res.nodes(), res.backtracks(), res.lastMRV(), res.seconds()
)
);
}