Skip to content

Commit c6372d5

Browse files
test(split-chunks): drive the discovery paths many sets take
Sparse sets reach their pairs through a shared member rather than by walking every pair, and enough of them outgrow the table the patterns are deduplicated in — neither path had a test, and the support scan never rejected a set.
1 parent 72b6229 commit c6372d5

1 file changed

Lines changed: 94 additions & 0 deletions

File tree

‎test/unitCases/ChunkSetIntersections.unittest.js‎

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ const {
44
discoverIntersections
55
} = require("../../lib/util/chunkSetIntersections");
66

7+
/**
8+
* Counts the bits of a number.
9+
* @param {number} value the number
10+
* @returns {number} how many bits are set
11+
*/
12+
const popcountOf = (value) => {
13+
let count = 0;
14+
for (let bit = value; bit !== 0; bit >>= 1) count += bit & 1;
15+
return count;
16+
};
17+
718
/**
819
* Runs discovery over sets written as member lists.
920
* @param {number[][]} sets the sets to intersect
@@ -259,6 +270,89 @@ describe("chunkSetIntersections", () => {
259270
]);
260271
});
261272

273+
describe("over many sets", () => {
274+
// Pairs of blocks: two sets sharing a block intersect to it. Each member
275+
// is held by few sets, so the pairs are reached through the members.
276+
const blockCount = 12;
277+
/** @type {number[][]} */
278+
const blockPairs = [];
279+
for (let first = 0; first < blockCount; first++) {
280+
for (let second = first + 1; second < blockCount; second++) {
281+
blockPairs.push([
282+
first * 2,
283+
first * 2 + 1,
284+
second * 2,
285+
second * 2 + 1
286+
]);
287+
}
288+
}
289+
290+
it("should reach a pair through the member they share", () => {
291+
const { intersections, capped } = discover(blockPairs);
292+
expect(capped).toBe(false);
293+
expect(intersections).toHaveLength(blockCount);
294+
for (const { members, support } of intersections) {
295+
expect(members).toHaveLength(2);
296+
expect(members[1]).toBe(members[0] + 1);
297+
expect(support).toHaveLength(blockCount - 1);
298+
}
299+
});
300+
301+
it("should leave out a set holding one member of an intersection", () => {
302+
// Each of these holds one member of the first block and nothing else of
303+
// it, so the support scan reaches them and drops them again
304+
const sets = [...blockPairs, [0, 100, 101], [1, 102, 103]];
305+
const { intersections } = discover(sets);
306+
const first = intersections.find(
307+
(intersection) =>
308+
intersection.members.length === 2 && intersection.members[0] === 0
309+
);
310+
expect(first).toEqual({
311+
members: [0, 1],
312+
support: blockPairs
313+
.map((_, index) => index)
314+
.filter((index) => blockPairs[index].includes(0))
315+
});
316+
});
317+
318+
it("should skip a pair a round before it already intersected", () => {
319+
const { intersections, capped } = discover(blockPairs, { depth: 2 });
320+
expect(capped).toBe(false);
321+
// A block is all two of these sets share, so a second round adds nothing
322+
expect(intersections).toHaveLength(blockCount);
323+
});
324+
325+
it("should report being cut short of a member's pairs", () => {
326+
const { intersections, capped } = discover(blockPairs, { maxWork: 8 });
327+
expect(capped).toBe(true);
328+
expect(intersections.length).toBeLessThan(blockCount);
329+
});
330+
331+
it("should hold more intersections than the sets it started from", () => {
332+
// Every five of eight members, so a round finds every smaller subset —
333+
// more patterns than the table was opened for
334+
/** @type {number[][]} */
335+
const sets = [];
336+
for (let mask = 0; mask < 256; mask++) {
337+
if (popcountOf(mask) !== 5) continue;
338+
sets.push(
339+
[0, 1, 2, 3, 4, 5, 6, 7].filter((member) => (mask >> member) & 1)
340+
);
341+
}
342+
expect(sets).toHaveLength(56);
343+
const { intersections, capped } = discover(sets, {
344+
depth: 1,
345+
maxIntersections: 1000
346+
});
347+
expect(capped).toBe(false);
348+
// Every subset of two, three and four of the eight members
349+
expect(intersections).toHaveLength(154);
350+
expect(new Set(intersections.map((i) => i.members.join(","))).size).toBe(
351+
154
352+
);
353+
});
354+
});
355+
262356
it("should hold intersections of more members than a word", () => {
263357
const wide = Array.from({ length: 70 }, (_, i) => i);
264358
const { intersections } = discover([

0 commit comments

Comments
 (0)