introduce bitloops

This commit is contained in:
mike
2026-01-17 04:35:53 +01:00
parent 47b33af09d
commit 3bd7a0f958
6 changed files with 95 additions and 100 deletions

View File

@@ -9,15 +9,6 @@ import lombok.experimental.Delegate;
import lombok.val;
import precomp.Neighbors9x8;
import precomp.Neighbors9x8.rci;
import puzzle.Export.Bit1029;
import puzzle.Export.DictEntryDTO;
import puzzle.Export.Gridded;
import puzzle.Export.Strings;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import static java.lang.Long.*;
import static java.lang.Long.numberOfTrailingZeros;
@@ -66,6 +57,18 @@ public class SwedishGenerator {
public static final long RANGE_0_624 = 624L - 0L + 1L;
public static final int CLUE_INDEX_MAX_SIZE = (288 | 3) + 1;
public static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
interface Bit1029 {
static long[] bit1029() { return new long[2048]; }
private static int wordIndex(int bitIndex) { return bitIndex >> 6; }
static boolean get(long[] bits, int bitIndex) { return (bits[wordIndex(bitIndex)] & 1L << bitIndex) != 0L; }
static void set(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; }
static void clear(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] &= ~(1L << bitIndex); }
}
static String padRight(String s, int n) {
if (s.length() >= n) return s;
return s + " ".repeat(n - s.length());
}
@AllArgsConstructor
public static class Pick {
@@ -88,24 +91,20 @@ public class SwedishGenerator {
@Accessors(fluent = true)
public static final class FillStats {
final public long nodes;
final public long backtracks;
final public double seconds;
final public int lastMRV;
public double simplicity;
}
public static record FillResult(boolean ok,
@Delegate FillStats stats) {
public static record FillResult(boolean ok, long nodes, long backtracks, @Delegate FillStats stats) {
static public long calcSimpel(Slotinfo[] slots) {
int k = 0;
long simpel = 0L;
for (var n = 1; n < slots.length; n++) {
if (slots[n].assign().w != X) {
if (slots[n].assign.w != X) {
k++;
simpel += Lemma.simpel(slots[n].assign().w);
simpel += Lemma.simpel(slots[n].assign.w);
}
}
simpel = k == 0 ? 0 : simpel / k;
@@ -176,52 +175,7 @@ public class SwedishGenerator {
static int unpackLetters(long w) { return (int) (w & LETTER_MASK); }
}
public static record Dict(
DictEntry[] index,
int length) {
public Dict(long[] wordz) {
var index = new DictEntryDTO[MAX_WORD_LENGTH_PLUS_ONE];
Arrays.setAll(index, i -> new DictEntryDTO(i));
for (var lemma : wordz) {
var L = Lemma.length(lemma);
var entry = index[L];
var idx = entry.words().size();
entry.words().add(lemma);
for (var i = 0; i < L; i++) entry.pos()[i][Lemma.byteAt(lemma, i) - 1].add(idx);
}
for (int i = MIN_LEN; i < index.length; i++) if (index[i].words().size() <= 0) throw new RuntimeException("No words for length " + i);
this(Arrays.stream(index).map(i -> {
var words = i.words().toArray();
int numWords = words.length;
int numLongs = (numWords + 63) >>> 6;
var bitsets = new long[i.pos().length * 26][numLongs];
for (int p = 0; p < i.pos().length; p++) {
for (int l = 0; l < 26; l++) {
var list = i.pos()[p][l];
var bs = bitsets[p * 26 + l];
for (int k = 0; k < list.size(); k++) {
int wordIdx = list.data()[k];
bs[wordIdx >>> 6] |= (1L << (wordIdx & 63));
}
}
}
return new DictEntry(words, bitsets, words.length, (words.length + 63) >>> 6);
}).toArray(DictEntry[]::new),
Arrays.stream(index).mapToInt(i -> i.words().size()).sum());
}
static Dict loadDict(String wordsPath) {
try {
var map = new LongArrayList(100_000);
Files.lines(Path.of(wordsPath), StandardCharsets.UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
return new Dict(map.toArray());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to load dictionary from " + wordsPath, e);
}
}
}
public static record Dict(DictEntry[] index, int length) { }
@AllArgsConstructor
@NoArgsConstructor
@@ -391,7 +345,7 @@ public class SwedishGenerator {
"%s %d/%d slots | nodes=%d | backtracks=%d | mrv=%d | %s",
bar, done, TOTAL, nodes, backtracks, lastMRV, elapsed
);
System.out.print("\r" + Strings.padRight(msg, 120));
System.out.print("\r" + padRight(msg, 120));
System.out.flush();
}
boolean placeWord(final int key, final long lo, final long hi, final long w) {
@@ -548,22 +502,7 @@ public class SwedishGenerator {
// final progress line
grid.lo = solver.glo;
grid.hi = solver.ghi;
var res = new FillResult(ok,
new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
if (!multiThreaded) {
System.out.print("\r" + Strings.padRight("", 120) + "\r");
System.out.flush();
}
// print a final progress line
if (Main.VERBOSE && !multiThreaded) {
System.out.println(
String.format(Locale.ROOT,
"[######################] %d/%d slots | nodes=%d | backtracks=%d | mrv=%d | %.1fs",
Slotinfo.wordCount(0, slots), TOTAL, res.nodes(), res.backtracks(), res.lastMRV(), res.seconds()
)
);
}
return res;
return new FillResult(ok, solver.nodes, solver.backtracks, new FillStats((System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
}
}