introduce bitloops

This commit is contained in:
mike
2026-01-19 19:11:31 +01:00
parent 1fa112ab65
commit 5d186ae0ba
4 changed files with 56 additions and 89 deletions

View File

@@ -332,7 +332,6 @@ public record Export() {
for (long w = lemma & Lemma.LETTER_MASK; w != 0; w >>>= 5, i++) {
pos[i][(int) ((w & 31) - 1)].add(idx);
}
// for (i = 0; i < L; i++) entry.pos()[i][Lemma.byteAt(lemma, i) - 1].add(idx);
}
for (int i = 2; i < index.length; i++) if (index[i].words().size() <= 0) throw new RuntimeException("No words for length " + i);
return new Dict(Arrays.stream(index).map(i -> {

View File

@@ -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());
}
}