introduce bitloops
This commit is contained in:
@@ -131,8 +131,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
long pattern;
|
long pattern;
|
||||||
final IntList[] intListBuffer = new IntList[MAX_WORD_LENGTH];
|
final IntList[] intListBuffer = new IntList[MAX_WORD_LENGTH];
|
||||||
final int[] undo = new int[2048];
|
final int[] undo = new int[2048];
|
||||||
final int[] inter1 = new int[160000];
|
final long[] bitset = new long[2500];
|
||||||
final int[] inter2 = new int[160000];
|
|
||||||
|
|
||||||
void setPattern(long p) { this.pattern = p; }
|
void setPattern(long p) { this.pattern = p; }
|
||||||
}
|
}
|
||||||
@@ -249,7 +248,7 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
|
|
||||||
static final record IntList(int[] data, int size) { }
|
static final record IntList(int[] data, int size) { }
|
||||||
|
|
||||||
static record DictEntry(Lemma[] words, IntList[][] pos) { }
|
static record DictEntry(Lemma[] words, IntList[][] pos, long[][] posBitsets) { }
|
||||||
|
|
||||||
public static record Lemma(int index, long word, byte len) {
|
public static record Lemma(int index, long word, byte len) {
|
||||||
|
|
||||||
@@ -298,12 +297,27 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = MIN_LEN; i < index.length; i++) if (index[i].words().size() <= 0) throw new RuntimeException("No words for length " + i);
|
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 -> new DictEntry(i.words().toArray(Lemma[]::new),
|
this(Arrays.stream(index).map(i -> {
|
||||||
Arrays.stream(i.pos())
|
var words = i.words().toArray(Lemma[]::new);
|
||||||
.map(ii -> Arrays.stream(ii).map(dto -> new IntList(dto.data(), dto.size()))
|
var pos = Arrays.stream(i.pos())
|
||||||
.toArray(IntList[]::new))
|
.map(ii -> Arrays.stream(ii).map(dto -> new IntList(dto.data(), dto.size()))
|
||||||
.toArray(IntList[][]::new)))
|
.toArray(IntList[]::new))
|
||||||
.toArray(DictEntry[]::new),
|
.toArray(IntList[][]::new);
|
||||||
|
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, pos, bitsets);
|
||||||
|
}).toArray(DictEntry[]::new),
|
||||||
Arrays.stream(index).mapToInt(i -> i.words().size()).sum());
|
Arrays.stream(index).mapToInt(i -> i.words().size()).sum());
|
||||||
}
|
}
|
||||||
static Dict loadDict(String wordsPath) {
|
static Dict loadDict(String wordsPath) {
|
||||||
@@ -701,53 +715,73 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CandidateInfo candidateInfoForPattern(Context ctx, DictEntry entry, int lenb) {
|
static CandidateInfo candidateInfoForPattern(Context ctx, DictEntry entry, int lenb) {
|
||||||
var pattern = ctx.pattern;
|
var pattern = ctx.pattern;
|
||||||
var listBuffer = ctx.intListBuffer;
|
|
||||||
var listCount = 0;
|
|
||||||
IntList tmp;
|
|
||||||
if (pattern == X) {
|
if (pattern == X) {
|
||||||
return new CandidateInfo(null, entry.words.length);
|
return new CandidateInfo(null, entry.words.length);
|
||||||
}
|
}
|
||||||
/*if (usedCharsInPattern(pattern) > len) {
|
|
||||||
var abc = usedCharsInPattern(pattern);
|
int numLongs = (entry.words.length + 63) >>> 6;
|
||||||
System.out.println(abc);
|
long[] res = ctx.bitset;
|
||||||
}*/
|
boolean first = true;
|
||||||
|
|
||||||
for (int i = 0, len = usedCharsInPattern(pattern); i < len; i++) {
|
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];
|
long[] bs = entry.posBitsets[i * 26 + (val - 1)];
|
||||||
}
|
if (first) {
|
||||||
}
|
System.arraycopy(bs, 0, res, 0, numLongs);
|
||||||
|
first = false;
|
||||||
// Sort constraints by size to optimize intersection
|
} else {
|
||||||
for (var i = 0; i < listCount - 1; i++) {
|
for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
|
||||||
for (var j = i + 1; j < listCount; j++) {
|
|
||||||
if (listBuffer[j].size() < listBuffer[i].size()) {
|
|
||||||
tmp = listBuffer[i];
|
|
||||||
listBuffer[i] = listBuffer[j];
|
|
||||||
listBuffer[j] = tmp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cur = listBuffer[0].data();
|
int count = 0;
|
||||||
var curLen = listBuffer[0].size();
|
for (int k = 0; k < numLongs; k++) count += Long.bitCount(res[k]);
|
||||||
if (listCount == 1) return new CandidateInfo(cur, curLen);
|
|
||||||
|
|
||||||
val b1 = ctx.inter1;
|
if (count == 0) return new CandidateInfo(null, 0);
|
||||||
val b2 = ctx.inter2;
|
|
||||||
var in = cur;
|
|
||||||
var out = b1;
|
|
||||||
|
|
||||||
for (var k = 1; k < listCount; k++) {
|
int[] indices = new int[count];
|
||||||
tmp = listBuffer[k];
|
int ki = 0;
|
||||||
curLen = intersectSorted(in, curLen, tmp.data(), tmp.size(), out);
|
for (int k = 0; k < numLongs; k++) {
|
||||||
in = out;
|
long w = res[k];
|
||||||
out = (out == b1) ? b2 : b1;
|
while (w != 0) {
|
||||||
if (curLen == 0) break;
|
int t = Long.numberOfTrailingZeros(w);
|
||||||
|
indices[ki++] = (k << 6) | t;
|
||||||
|
w &= w - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CandidateInfo(in, curLen);
|
return new CandidateInfo(indices, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int candidateCountForPattern(Context ctx, DictEntry entry) {
|
||||||
|
long pattern = ctx.pattern;
|
||||||
|
if (pattern == X) return entry.words.length;
|
||||||
|
|
||||||
|
int numLongs = (entry.words.length + 63) >>> 6;
|
||||||
|
long[] res = ctx.bitset;
|
||||||
|
boolean first = true;
|
||||||
|
|
||||||
|
for (int i = 0, len = usedCharsInPattern(pattern); i < len; i++) {
|
||||||
|
int val = (int) ((pattern >>> (i * 5)) & 31);
|
||||||
|
if (val != 0) {
|
||||||
|
long[] bs = entry.posBitsets[i * 26 + (val - 1)];
|
||||||
|
if (first) {
|
||||||
|
System.arraycopy(bs, 0, res, 0, numLongs);
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
for (int k = 0; k < numLongs; k++) res[k] &= bs[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first) return entry.words.length; // should not happen if pattern != X
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (int k = 0; k < numLongs; k++) count += Long.bitCount(res[k]);
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
public FillResult fillMask(Grid mask, DictEntry[] dictIndex,
|
public FillResult fillMask(Grid mask, DictEntry[] dictIndex,
|
||||||
int timeLimitMs) {
|
int timeLimitMs) {
|
||||||
@@ -805,24 +839,25 @@ public record SwedishGenerator(Rng rng) {
|
|||||||
var entry = dictIndex[s.len()];
|
var entry = dictIndex[s.len()];
|
||||||
if (entry == null) return PICK_NOT_DONE;
|
if (entry == null) return PICK_NOT_DONE;
|
||||||
ctx.pattern = patternForSlot(grid, s);
|
ctx.pattern = patternForSlot(grid, s);
|
||||||
var info = candidateInfoForPattern(ctx, entry, s.len());
|
int count = candidateCountForPattern(ctx, entry);
|
||||||
|
|
||||||
if (info.count == 0) return PICK_NOT_DONE;
|
if (count == 0) return PICK_NOT_DONE;
|
||||||
if (best == null
|
if (best == null
|
||||||
|| info.count < bestInfo.count
|
|| count < bestInfo.count
|
||||||
|| (info.count == bestInfo.count && slotScores[i] > bestScore)) {
|
|| (count == bestInfo.count && slotScores[i] > bestScore)) {
|
||||||
best = s;
|
best = s;
|
||||||
bestScore = slotScores[i];
|
bestScore = slotScores[i];
|
||||||
if (info.indices != null && (info.indices == ctx.inter1 || info.indices == ctx.inter2)) {
|
bestInfo = new CandidateInfo(null, count);
|
||||||
bestInfo = new CandidateInfo(Arrays.copyOf(info.indices, info.count), info.count);
|
if (count <= 1) break;
|
||||||
} else {
|
|
||||||
bestInfo = info;
|
|
||||||
}
|
|
||||||
if (info.count <= 1) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best == null) return PICK_DONE;
|
if (best == null) return PICK_DONE;
|
||||||
|
|
||||||
|
// Re-calculate for the best slot to get actual indices
|
||||||
|
ctx.pattern = patternForSlot(grid, best);
|
||||||
|
bestInfo = candidateInfoForPattern(ctx, dictIndex[best.len()], best.len());
|
||||||
|
|
||||||
return new Pick(best, bestInfo, false);
|
return new Pick(best, bestInfo, false);
|
||||||
}
|
}
|
||||||
boolean backtrack(int depth) {
|
boolean backtrack(int depth) {
|
||||||
|
|||||||
Reference in New Issue
Block a user