Skip to content

Commit

Permalink
🚴 perf: Scan middle snake only once.
Browse files Browse the repository at this point in the history
Fixes #19.
  • Loading branch information
make-github-pseudonymous-again committed Jun 3, 2021
1 parent 6c6413d commit da6d7e5
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 31 deletions.
74 changes: 74 additions & 0 deletions src/backwardExtend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import assert from 'assert';

import bound from './bound.js';
import longestCommonSuffix from './longestCommonSuffix.js';
/**
* Diagonal backward extension without yield.
*
* @param {number} center
* @param {number} D
* @param {Int32Array} V
* @param {Function} eq
* @param {number} li
* @param {number} lj
* @param {number} ri
* @param {number} rj
* @param {number} Delta
*/
export default function backwardExtend(
center,
D,
V,
eq,
li,
lj,
ri,
rj,
Delta,
) {
assert(ri > rj && li > lj);
// NOTE: We make the bounding box as small as possible.
// This should save roughly half of the computation time compared to
// letting LB = -D and UB = D.
const LB = -bound(D, li - lj);
const UB = bound(D, ri - rj);
assert(LB <= UB);
assert(LB !== D);
assert(UB !== -D);

console.debug('beg backwardExtend', {
center,
D,
V,
eq,
li,
lj,
ri,
rj,
LB,
UB,
Delta,
});

for (let k = LB; k <= UB; k += 2) {
const x = V[center + k];
const y = x - (k + Delta);
console.debug({k, x, lj, y, rj});

if (x >= lj && y >= rj && x <= li && y <= ri) {
V[center + k] = longestCommonSuffix(eq, x, lj, y, rj);
}
}

console.debug('end backwardExtend', {
center,
D,
V,
eq,
li,
lj,
ri,
rj,
Delta,
});
}
27 changes: 4 additions & 23 deletions src/backwardStep.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import assert from 'assert';

import bound from './bound.js';
import longestCommonSuffix from './longestCommonSuffix.js';
/**
* Diagonal backward step without yielding.
* Diagonal backward step without yield.
*
* @param {number} center
* @param {number} D
Expand Down Expand Up @@ -46,39 +45,21 @@ export default function backwardStep(center, D, V, eq, li, lj, ri, rj, Delta) {
const k = LB;
const xp = V[cx + k];
const yp = V[cy + k];
const x = k !== -D && xp > yp ? yp : xp - 1;
const y = x - (k + Delta);
console.debug({k, x, lj, y, rj});

if (x >= lj && y >= rj && x <= li && y <= ri) {
V[center + k] = longestCommonSuffix(eq, x, lj, y, rj);
}
V[center + k] = k !== -D && xp > yp ? yp : xp - 1;

for (let k = LB + 2; k < UB; k += 2) {
assert(k !== -D && k !== D);
const xp = V[cx + k];
const yp = V[cy + k];
const x = xp > yp ? yp : xp - 1;
const y = x - (k + Delta);
console.debug({k, x, lj, y, rj});

if (x >= lj && y >= rj && x <= li && y <= ri) {
V[center + k] = longestCommonSuffix(eq, x, lj, y, rj);
}
V[center + k] = xp > yp ? yp : xp - 1;
}

if (UB !== LB) {
const k = UB;
const xp = V[cx + k];
const yp = V[cy + k];
assert(k === D || xp > yp);
const x = yp;
const y = x - (k + Delta);
console.debug({k, x, lj, y, rj});

if (x >= lj && y >= rj && x <= li && y <= ri) {
V[center + k] = longestCommonSuffix(eq, x, lj, y, rj);
}
V[center + k] = yp;
}

console.debug('end backwardStep', {
Expand Down
9 changes: 4 additions & 5 deletions src/forwardStep.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import assert from 'assert';

import bound from './bound.js';
import longestCommonPrefix from './longestCommonPrefix.js';
/**
* Diagonal forward step.
* Diagonal forward step with yield.
*
* @param {number} center
* @param {number} D
Expand Down Expand Up @@ -53,7 +52,7 @@ export default function* forwardStep(center, D, V, eq, li, lj, ri, rj, Delta) {
console.debug({k, x, lj, y, rj});

if (x <= lj && y <= rj && x >= li && y >= ri) {
V[center + k] = longestCommonPrefix(eq, x, lj, y, rj);
V[center + k] = x;
yield k;
}

Expand All @@ -66,7 +65,7 @@ export default function* forwardStep(center, D, V, eq, li, lj, ri, rj, Delta) {
console.debug({k, x, lj, y, rj});

if (x <= lj && y <= rj && x >= li && y >= ri) {
V[center + k] = longestCommonPrefix(eq, x, lj, y, rj);
V[center + k] = x;
yield k;
}
}
Expand All @@ -80,7 +79,7 @@ export default function* forwardStep(center, D, V, eq, li, lj, ri, rj, Delta) {
console.debug({k, x, lj, y, rj});

if (x <= lj && y <= rj && x >= li && y >= ri) {
V[center + k] = longestCommonPrefix(eq, x, lj, y, rj);
V[center + k] = x;
yield k;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export {default as backwardExtend} from './backwardExtend.js';
export {default as backwardStep} from './backwardStep.js';
export {default as bound} from './bound.js';
export {default as boundAlloc} from './boundAlloc.js';
Expand Down
8 changes: 6 additions & 2 deletions src/oneWay.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import assert from 'assert';

import oneWayAlloc from './oneWayAlloc.js';
import forwardStep from './forwardStep.js';
import longestCommonPrefix from './longestCommonPrefix.js';

/**
* Scan from begin to end.
Expand All @@ -27,12 +28,15 @@ const oneWay = (MAX, eq, li, lj, ri, rj) => {
const Delta0 = li - ri;
for (let D = 1; D <= MAX; ++D) {
for (const k of forwardStep(center, D, V, eq, li, lj, ri, rj, Delta0)) {
const x = V[center + k];
const y = x - (k + Delta0);
let x = V[center + k];
let y = x - (k + Delta0);
x = longestCommonPrefix(eq, x, lj, y, rj);
y = x - (k + Delta0);
if (x === lj && y === rj)
return {
distance: D,
};
V[center + k] = x;
}
}

Expand Down
12 changes: 11 additions & 1 deletion src/twoWayScan.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import assert from 'assert';

import forwardStep from './forwardStep.js';
import backwardStep from './backwardStep.js';
import backwardExtend from './backwardExtend.js';
import longestCommonPrefix from './longestCommonPrefix.js';
import longestCommonSuffix from './longestCommonSuffix.js';

/**
* Scan from begin to middle and end to middle.
Expand Down Expand Up @@ -42,12 +45,15 @@ const twoWayScan = (MAX, V, centerF, centerB, eq, li, lj, ri, rj) => {
for (let D = 1; D <= HALF_MAX; ++D) {
if (2 * D > MAX + parityDelta) break;
for (const k of forwardStep(centerF, D, V, eq, li, lj, ri, rj, Delta0)) {
const x = V[centerF + k];
const y = x - (k + Delta0);
V[centerF + k] = longestCommonPrefix(eq, x, lj, y, rj);
if (k - Delta < -(D - parityDelta)) continue;
if (k - Delta > D - parityDelta) continue;
if (V[centerF + k] < V[centerB + k - Delta]) continue; // TODO this scans the snake twice
return {
k: k + Delta0,
xBegin: V[centerB + k - Delta],
xBegin: longestCommonSuffix(eq, x, li, y, ri),
xEnd: V[centerF + k],
distance: 2 * D - parityDelta,
distanceLeft: D,
Expand All @@ -57,6 +63,10 @@ const twoWayScan = (MAX, V, centerF, centerB, eq, li, lj, ri, rj) => {

if (D === HALF_MAX) break;

if (D > parityDelta) {
backwardExtend(centerB, D - parityDelta, V, eq, lj, li, rj, ri, Delta1);
}

backwardStep(centerB, D + 1 - parityDelta, V, eq, lj, li, rj, ri, Delta1);
}

Expand Down

0 comments on commit da6d7e5

Please sign in to comment.