introduce bitloops

This commit is contained in:
mike
2026-01-12 03:52:52 +01:00
parent 678add4cb9
commit 123cdbdc01
3 changed files with 47 additions and 37 deletions

View File

@@ -58,11 +58,11 @@ public record Export() {
static long pack(int r, int c) { return (((long) r) << 32) ^ (c & 0xFFFFFFFFL); } static long pack(int r, int c) { return (((long) r) << 32) ^ (c & 0xFFFFFFFFL); }
long l1, l2; long l1, l2;
public boolean get(int bitIndex) { public boolean get(int bitIndex) {
if (bitIndex < 64) return (l1 & (1L << bitIndex)) != 0L; if ((bitIndex & 64) == 0) return (l1 & (1L << bitIndex)) != 0L;
return (l2 & (1L << (bitIndex & 63))) != 0L; return (l2 & (1L << (bitIndex & 63))) != 0L;
} }
public void set(int bitIndex) { public void set(int bitIndex) {
if (bitIndex < 64) this.l1 |= 1L << bitIndex; if ((bitIndex & 64) == 0) this.l1 |= 1L << bitIndex;
else this.l2 |= 1L << (bitIndex & 63); else this.l2 |= 1L << (bitIndex & 63);
} }
public void clear() { public void clear() {

View File

@@ -57,7 +57,6 @@ public record SwedishGenerator(Rng rng) {
static final double SIZED = (double) SIZE;// ~18 static final double SIZED = (double) SIZE;// ~18
static final int TARGET_CLUES = SIZE >> 2; static final int TARGET_CLUES = SIZE >> 2;
static final int MAX_WORD_LENGTH = C <= R ? C : R; static final int MAX_WORD_LENGTH = C <= R ? C : R;
static final int MAX_WORD_LENGTH7 = MAX_WORD_LENGTH * 7;
static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1; static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1;
static final int MIN_LEN = Config.MIN_LEN; static final int MIN_LEN = Config.MIN_LEN;
static final int MIN_LEN7 = Config.MIN_LEN * 7; static final int MIN_LEN7 = Config.MIN_LEN * 7;
@@ -123,8 +122,8 @@ public record SwedishGenerator(Rng rng) {
static final class Context { static final class Context {
final int[] covH = new int[SIZE]; final Bit covH2 = new Bit();
final int[] covV = new int[SIZE]; final Bit covV2 = new Bit();
final int[] cellCount = new int[SIZE]; final int[] cellCount = new int[SIZE];
final int[] stack = new int[SIZE]; final int[] stack = new int[SIZE];
final Bit seen = new Bit(); final Bit seen = new Bit();
@@ -188,35 +187,32 @@ public record SwedishGenerator(Rng rng) {
void setByteAt(int idx, byte ch) { g[idx] = ch; } void setByteAt(int idx, byte ch) { g[idx] = ch; }
void setClue(int idx, byte ch) { void setClue(int idx, byte ch) {
g[idx] = ch; g[idx] = ch;
if (idx < 64) lo |= (1L << idx); if ((idx & 64) == 0) lo |= (1L << idx);
else hi |= (1L << (idx & 63)); else hi |= (1L << (idx & 63));
} }
void clearletter(int idx) { g[idx] = DASH; } void clearletter(int idx) { g[idx] = DASH; }
void clearClue(int idx) { void clearClue(int idx) {
g[idx] = DASH; g[idx] = DASH;
if (idx < 64) lo &= ~(1L << idx); if ((idx & 64) == 0) lo &= ~(1L << idx);
else hi &= ~(1L << (idx & 63)); else hi &= ~(1L << (idx & 63));
} }
static boolean isDigit(byte b) { return (b & B48) == B48; } static boolean isDigit(byte b) { return (b & B48) == B48; }
boolean isDigitAt(int index) { return isDigit(g[index]); } boolean isDigitAt(int index) { return isDigit(g[index]); }
boolean isClue(long index) { boolean isClue(long index) {
if (index < 64) return ((lo >> index) & 1L) != X; if ((index & 64) == 0) return ((lo >> index) & 1L) != X;
return ((hi >> (index & 63)) & 1L) != X; return ((hi >> (index & 63)) & 1L) != X;
} }
boolean isClue(int index) { boolean isClue(int index) {
if (index < 64) return ((lo >> index) & 1L) != 0; if ((index & 64) == 0) return ((lo >> index) & 1L) != 0;
return ((hi >> (index & 63)) & 1L) != 0; return ((hi >> (index & 63)) & 1L) != 0;
} }
boolean notClue(long index) { boolean notClue(long index) {
if (index < 64) return ((lo >> index) & 1L) == X; if ((index & 64) == 0) return ((lo >> index) & 1L) == X;
return ((hi >> (index & 63)) & 1L) == X;
}
boolean notClue(int index) {
if (index < 64) return ((lo >> index) & 1L) == X;
return ((hi >> (index & 63)) & 1L) == X; return ((hi >> (index & 63)) & 1L) == X;
} }
boolean notClue(int index) { return ((index & 64) == 0) ? ((lo >> index) & 1L) == X : ((hi >> (index & 63)) & 1L) == X; }
boolean clueless(int idx) { boolean clueless(int idx) {
if (idx < 64) { if ((idx & 64) == 0) {
val test = (1L << idx); val test = (1L << idx);
if ((test & lo) == X) return false; if ((test & lo) == X) return false;
g[idx] = DASH; g[idx] = DASH;
@@ -257,6 +253,9 @@ public record SwedishGenerator(Rng rng) {
public static record Lemma(int index, long word, byte len) { public static record Lemma(int index, long word, byte len) {
static int LEMMA_COUNTER = 0; static int LEMMA_COUNTER = 0;
static long pack(String word) {
return pack(word.getBytes(US_ASCII));
}
static long pack(byte[] b) { static long pack(byte[] b) {
long w = 0; long w = 0;
for (var i = 0; i < b.length; i++) w |= ((long) b[i] & ~64) << (i * 5); for (var i = 0; i < b.length; i++) w |= ((long) b[i] & ~64) << (i * 5);
@@ -394,7 +393,7 @@ public record SwedishGenerator(Rng rng) {
long packed = nbrs16.path()[clueIdx]; long packed = nbrs16.path()[clueIdx];
int n = (int) (packed >>> 56) * 7, k, idx; int n = (int) (packed >>> 56) * 7, k, idx;
var horiz = Slot.horiz(d) ? covH : covV; var horiz = Slot.horiz(d) ? covH : covV;
for (k = 0; k < n && k < MAX_WORD_LENGTH7; k += 7) { for (k = 0; k < n; k += 7) {
idx = (int) ((packed >>> (k)) & 0x7F); idx = (int) ((packed >>> (k)) & 0x7F);
if (grid.isClue(idx)) break; if (grid.isClue(idx)) break;
horiz[idx] += 1; horiz[idx] += 1;
@@ -408,10 +407,12 @@ public record SwedishGenerator(Rng rng) {
long maskFitness(Grid grid) { long maskFitness(Grid grid) {
var ctx = CTX.get(); var ctx = CTX.get();
var covH = ctx.covH; var covH = ctx.covH2;
var covV = ctx.covV; var covV = ctx.covV2;
Arrays.fill(covH, 0, SIZE, 0); covH.clear();
Arrays.fill(covV, 0, SIZE, 0); covV.clear();
/*Arrays.fill(covH, 0, SIZE, 0);
Arrays.fill(covV, 0, SIZE, 0);*/
long lo_cl = grid.lo, hi_cl = grid.hi; long lo_cl = grid.lo, hi_cl = grid.hi;
long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) * 16000L); long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) * 16000L);
boolean hasSlots = false; boolean hasSlots = false;
@@ -424,10 +425,10 @@ public record SwedishGenerator(Rng rng) {
long packed = nbrs16.path()[clueIdx]; long packed = nbrs16.path()[clueIdx];
int n = (int) (packed >>> 56) * 7, k, idx; int n = (int) (packed >>> 56) * 7, k, idx;
var horiz = Slot.horiz(d) ? covH : covV; var horiz = Slot.horiz(d) ? covH : covV;
for (k = 0; k < n && k < MAX_WORD_LENGTH7; k += 7) { for (k = 0; k < n; k += 7) {
idx = (int) ((packed >>> (k)) & 0x7F); idx = (int) ((packed >>> (k)) & 0x7F);
if (grid.isClue(idx)) break; if (grid.isClue(idx)) break;
horiz[idx] += 1; horiz.set(idx);
} }
if (k > 0) { if (k > 0) {
hasSlots = true; hasSlots = true;
@@ -470,10 +471,10 @@ public record SwedishGenerator(Rng rng) {
int clueIdx = i + Long.numberOfTrailingZeros(bits); int clueIdx = i + Long.numberOfTrailingZeros(bits);
var rci = IT[clueIdx]; 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()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
var h = covH[clueIdx]; var h = covH.get(clueIdx);
var v = covV[clueIdx]; var v = covV.get(clueIdx);
if (h == 0 && v == 0) penalty += 1500; if (!h && !v) penalty += 1500;
else if (h > 0 && v > 0) { /* ok */ } else if (h + v == 1) penalty += 200; else if (h && v) { /* ok */ } else if (h | v) penalty += 200;
else penalty += 600; else penalty += 600;
} }
} }
@@ -523,10 +524,10 @@ public record SwedishGenerator(Rng rng) {
if (out.g[i] != ch) { if (out.g[i] != ch) {
out.g[i] = ch; out.g[i] = ch;
if (Grid.isDigit(ch)) { if (Grid.isDigit(ch)) {
if (i < 64) bo0 |= (1L << i); if ((i & 64) == 0) bo0 |= (1L << i);
else bo1 |= (1L << (i & 63)); else bo1 |= (1L << (i & 63));
} else { } else {
if (i < 64) bo0 &= ~(1L << i); if ((i & 64) == 0) bo0 &= ~(1L << i);
else bo1 &= ~(1L << (i & 63)); else bo1 &= ~(1L << (i & 63));
} }
} }
@@ -615,6 +616,11 @@ public record SwedishGenerator(Rng rng) {
//return pop.get(0).grid; //return pop.get(0).grid;
return best.grid; return best.grid;
} }
static int usedCharsInPattern(long p) {
if (p == 0) return 0;
int highestBit = 63 - Long.numberOfLeadingZeros(p); // 0-based
return (highestBit / 5) + 1;
}
static long patternForSlot(Grid grid, Slot s) { static long patternForSlot(Grid grid, Slot s) {
long p = 0; long p = 0;
for (int i = 0, len = s.len(); i < len; i++) { for (int i = 0, len = s.len(); i < len; i++) {
@@ -654,23 +660,27 @@ public record SwedishGenerator(Rng rng) {
return true; return true;
} }
static CandidateInfo candidateInfoForPattern(Context ctx, DictEntry entry, int len) { static CandidateInfo candidateInfoForPattern(Context ctx, DictEntry entry, int lenb) {
var pattern = ctx.pattern; var pattern = ctx.pattern;
var listBuffer = ctx.intListBuffer; var listBuffer = ctx.intListBuffer;
var listCount = 0; var listCount = 0;
IntList tmp; IntList tmp;
for (var i = 0; i < len; i++) { if (pattern == X) {
return new CandidateInfo(null, entry.words.length);
}
/*if (usedCharsInPattern(pattern) > len) {
var abc = usedCharsInPattern(pattern);
System.out.println(abc);
}*/
for (int i = 0, len = usedCharsInPattern(pattern); i < len; i++) {
int val = (int) ((pattern >>> (i * 5)) & 31); int val = (int) ((pattern >>> (i * 5)) & 31);
if (val != 0) { if (val != 0) {
listBuffer[listCount++] = entry.pos[i][val - 1]; listBuffer[listCount++] = entry.pos[i][val - 1];
} else {
//System.out.println("?");
} }
} }
if (listCount == 0) {
//return CANDIDATES[entry.words.length];
return new CandidateInfo(null, entry.words.length);
}
// Sort constraints by size to optimize intersection // Sort constraints by size to optimize intersection
for (var i = 0; i < listCount - 1; i++) { for (var i = 0; i < listCount - 1; i++) {
for (var j = i + 1; j < listCount; j++) { for (var j = i + 1; j < listCount; j++) {

View File

@@ -167,8 +167,8 @@ public class MainTest {
// Regression baseline for seed search starting at 12347, pop 4, gens 20 // Regression baseline for seed search starting at 12347, pop 4, gens 20
Assertions.assertEquals(12348, foundSeed, "Found seed changed"); Assertions.assertEquals(12348, foundSeed, "Found seed changed");
Assertions.assertEquals(18, res.filled().clueMap().size(), "Number of assigned words changed"); Assertions.assertEquals(18, res.filled().clueMap().size(), "Number of assigned words changed");
Assertions.assertEquals(Lemma.pack(new byte[]{ 'L', 'E', 'L', 'I', 'J', 'K', 'S' }), res.filled().clueMap().get(451).word()); Assertions.assertEquals(Lemma.pack("VERPATS"), res.filled().clueMap().get(74).word());
Assertions.assertEquals(73207692597665799L, res.filled().grid().grid().lo); Assertions.assertEquals(301794542151533187L, res.filled().grid().grid().lo);
Assertions.assertEquals(193L, res.filled().grid().grid().hi); Assertions.assertEquals(193L, res.filled().grid().grid().hi);
} }
@Test @Test