Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@

import { assert } from 'chai';

import { DeletionQuotientSpur, InsertionQuotientSpur } from '@keymanapp/lm-worker/test-index';

import { constituentPaths } from "./constituentPaths.js";
import { toSpurTypeSequence } from './toSpurTypeSequence.js';
import { buildCantLinearFixture } from './buildCantLinearFixture.js';
import { buildAlphabeticClusterFixtures } from './buildAlphabeticClusteredFixture.js';
import { buildQuotientDocFixture } from './buildQuotientDocFixture.js';

describe('constituentPaths', () => {
it('includes a single entry array when all parents are SearchQuotientSpurs', () => {
Expand Down Expand Up @@ -42,4 +46,50 @@ describe('constituentPaths', () => {
return p;
}));
});

describe('for the final quotient-graph doc example', () => {
it('handles insertion-only quotient-graph paths', () => {
const { sc2 } = buildQuotientDocFixture().nodes;

const sc2Constituents = constituentPaths(sc2);
assert.equal(sc2Constituents.length, 1);
sc2Constituents.forEach(s => s.forEach(p => assert.isTrue(p instanceof InsertionQuotientSpur)));
});

it('handles deletion-only quotient-graph paths', () => {
const { k2c0 } = buildQuotientDocFixture().nodes;

const k2c0Constituents = constituentPaths(k2c0);
assert.equal(k2c0Constituents.length, 1);
k2c0Constituents.forEach(s => s.forEach(p => assert.isTrue(p instanceof DeletionQuotientSpur)));
});

it('does not emit sequences with inserts immediately following deletes', () => {
const { k2c3 } = buildQuotientDocFixture().nodes;

const k2c3Constituents = constituentPaths(k2c3);

const shouldNotOccur = k2c3Constituents.find((seq) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From devin.ai. Might be better to use k2c3Constituents.some(.... (Same in the next test)

const typeSeq = toSpurTypeSequence(seq);
return typeSeq.find((type, index) => {
return type == 'delete' && typeSeq[index+1] == 'insert';
});
});
assert.isNotOk(shouldNotOccur);
});

it('does emit sequences with deletes immediately following inserts', () => {
const { k2c3 } = buildQuotientDocFixture().nodes;

const k2c3Constituents = constituentPaths(k2c3);

const shouldOccur = k2c3Constituents.find((seq) => {
const typeSeq = toSpurTypeSequence(seq);
return typeSeq.find((type, index) => {
return type == 'insert' && typeSeq[index+1] == 'delete';
});
});
assert.isOk(shouldOccur);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*/

import {
DeletionQuotientSpur,
InsertionQuotientSpur,
SearchQuotientCluster,
SearchQuotientNode,
SearchQuotientRoot,
Expand All @@ -29,6 +31,28 @@ export function constituentPaths(node: SearchQuotientNode): SearchQuotientSpur[]
const parentPaths = constituentPaths(node.parents[0]);
let pathsToExtend = parentPaths;

if(node instanceof InsertionQuotientSpur) {
pathsToExtend = pathsToExtend.filter(s => {
const tail = s[s.length - 1];

// Deletion nodes and modules should always be ordered after those for
// insertion in order to avoid duplicating search paths. (Insertions may
// stick to the right of a root, while deletions always process inputs; insertions
// may thus precede deletions.)
//
// Also, internally, insertion edges are not built after deletion (or empty) edges.
if(tail instanceof DeletionQuotientSpur) {
return false;
} else if(tail.insertLength == 0 && tail.leftDeleteLength == 0) {
// Insertions should also not appear after empty nodes; there's no net
// difference between inserting before and inserting after.
return false;
}

return true;
});
}

if(parentPaths.length > 0) {
return pathsToExtend.map(p => {
p.push(node);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
DeletionQuotientSpur,
InsertionQuotientSpur,
SearchQuotientNode,
SubstitutionQuotientSpur
} from "@keymanapp/lm-worker/test-index";

export function toSpurTypeSequence(spurs: SearchQuotientNode[]): ('insert' | 'delete' | 'substitute' | 'legacy')[] {
return spurs.map(s => {
if(s instanceof InsertionQuotientSpur) {
return 'insert';
} else if(s instanceof DeletionQuotientSpur) {
return 'delete';
} else if(s instanceof SubstitutionQuotientSpur) {
return 'substitute';
} else {
return 'legacy';
}
})
}
Loading