mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-30 04:07:42 +00:00
docs(web): add doc-comments for ClassicalDistanceCalculation class, methods, and helpers
This commit is contained in:
parent
69d162696a
commit
ed0c08ee34
1 changed files with 146 additions and 6 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { SENTINEL_CODE_UNIT } from '@keymanapp/models-templates';
|
||||
import { SENTINEL_CODE_UNIT } from "@keymanapp/models-templates";
|
||||
|
||||
/**
|
||||
* The human-readable names for legal edit-operation edges on the edit path.
|
||||
|
|
@ -209,8 +209,9 @@ export interface DistanceCalcOptions {
|
|||
* In short: Used to optimize calculations for low edit-distance checks, then
|
||||
* expanded if/as necessary if a greater edit distance is requested.
|
||||
*
|
||||
* Reference:
|
||||
* https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm#Possible_modifications
|
||||
* References:
|
||||
* - https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
|
||||
* - https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm#Possible_modifications
|
||||
* - Motivating statement: "if we are only interested in the distance if it
|
||||
* is smaller than a threshold..."
|
||||
*/
|
||||
|
|
@ -306,6 +307,15 @@ export class ClassicalDistanceCalculation<
|
|||
return this._diagonalWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the internal indices (within `this.resolvedDistances`)
|
||||
* corresponding to the provided external (non-sparsified) indices and
|
||||
* specified diagonal width.
|
||||
* @param r
|
||||
* @param c
|
||||
* @param width
|
||||
* @returns
|
||||
*/
|
||||
private getTrueIndex(r: number, c: number, width: number): {row: number, col: number, sparse: boolean} {
|
||||
let retVal = {
|
||||
row: r,
|
||||
|
|
@ -320,7 +330,16 @@ export class ClassicalDistanceCalculation<
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the optimal intermediate edit-cost at the specified indices.
|
||||
* @param i
|
||||
* @param j
|
||||
* @param width
|
||||
* @returns
|
||||
*/
|
||||
public getCostAt(i: number, j: number, width: number = this.diagonalWidth): number {
|
||||
// Note: i and j are external, "non-sparsified" indices.
|
||||
|
||||
// Check for and handle the set of fixed-value virtualized indices.
|
||||
if(i < 0 || j < 0) {
|
||||
if(i == -1 && j >= -1) {
|
||||
|
|
@ -502,6 +521,17 @@ export class ClassicalDistanceCalculation<
|
|||
return pathBuilder.validPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the specified indices in order to determine the minimum edit cost
|
||||
* required to reach them, saving the intermediate results within the internal
|
||||
* `.resolvedDistances` buffer.
|
||||
* @param buffer
|
||||
* @param r
|
||||
* @param c
|
||||
* @param insertCost
|
||||
* @param deleteCost
|
||||
* @returns
|
||||
*/
|
||||
private static initialCostAt<TUnit, TOpSet>(
|
||||
buffer: ClassicalDistanceCalculation<TUnit, TOpSet>,
|
||||
r: number,
|
||||
|
|
@ -523,6 +553,17 @@ export class ClassicalDistanceCalculation<
|
|||
return Math.min(substitutionCost, deletionCost, insertionCost, transpositionCost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims this calculation object, yielding the version representing only the
|
||||
* range of initial `input` and `match` entries specified.
|
||||
*
|
||||
* Note that this method cannot be used to trim entries from the start; only entries
|
||||
* from the end of both the `input` and `match` sequences may be trimmed.
|
||||
*
|
||||
* @param inputLength The number of initial `input` entries to preserve
|
||||
* @param matchLength The number of initial `match` entries to preserve
|
||||
* @returns
|
||||
*/
|
||||
getSubset(inputLength: number, matchLength: number): ClassicalDistanceCalculation<TUnit, TOpSet> {
|
||||
let trimmedInstance = new ClassicalDistanceCalculation<TUnit, TOpSet>(this);
|
||||
|
||||
|
|
@ -558,13 +599,28 @@ export class ClassicalDistanceCalculation<
|
|||
return trimmedInstance;
|
||||
}
|
||||
|
||||
// Inputs add an extra row / first index entry.
|
||||
/**
|
||||
* Adds a new entry for the sequence labeled "input" for edit-distance calculations and
|
||||
* calculates related edit-distance costs.
|
||||
* @param token
|
||||
* @returns
|
||||
*/
|
||||
addInputChar(token: TUnit): this {
|
||||
const returnBuffer = new ClassicalDistanceCalculation<TUnit, TOpSet>(this);
|
||||
returnBuffer._addInputChar(token);
|
||||
return returnBuffer as this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper to `addInputChar` is designed to facilitate calculation of
|
||||
* subclass-specific functionality when new `input`-sequence characters are
|
||||
* added while still supporting `public`-level immutable encapsulation for
|
||||
* both parent and the child.
|
||||
*
|
||||
* This is leveraged by the `SegmentableDistanceCalculation` type.
|
||||
* @param token
|
||||
* @returns
|
||||
*/
|
||||
protected _addInputChar(token: TUnit) {
|
||||
// Insert a row, even if we don't actually do anything with it yet.
|
||||
// Initialize all entries with Number.MAX_VALUE, as `undefined` use leads to JS math issues.
|
||||
|
|
@ -584,12 +640,28 @@ export class ClassicalDistanceCalculation<
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new entry for the sequence labeled "match" for edit-distance calculations and
|
||||
* calculates related edit-distance costs.
|
||||
* @param token
|
||||
* @returns
|
||||
*/
|
||||
addMatchChar(token: TUnit): this {
|
||||
const returnBuffer = new ClassicalDistanceCalculation<TUnit, TOpSet>(this);
|
||||
returnBuffer._addMatchChar(token);
|
||||
return returnBuffer as this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper to `addMatchChar` is designed to facilitate calculation of
|
||||
* subclass-specific functionality when new `match`-sequence characters are
|
||||
* added while still supporting `public`-level immutable encapsulation for
|
||||
* both parent and the child.
|
||||
*
|
||||
* This is leveraged by the `SegmentableDistanceCalculation` type.
|
||||
* @param token
|
||||
* @returns
|
||||
*/
|
||||
protected _addMatchChar(token: TUnit) {
|
||||
this._matchSequence.push(token);
|
||||
|
||||
|
|
@ -607,6 +679,11 @@ export class ClassicalDistanceCalculation<
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the edit-distance diagonal's width, allowing a greater range of edits to be properly
|
||||
* modeled and considered.
|
||||
* @returns
|
||||
*/
|
||||
public increaseMaxDistance(): this {
|
||||
let returnBuffer = new ClassicalDistanceCalculation<TUnit, TOpSet>(this);
|
||||
returnBuffer._diagonalWidth++;
|
||||
|
|
@ -712,6 +789,18 @@ export class ClassicalDistanceCalculation<
|
|||
return returnBuffer as this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method of `increaseMaxDistance`, this method helps to update
|
||||
* existing edits should newly-considered edits provide a net lower cost than
|
||||
* was previously visible due to the original limited range under
|
||||
* consideration for edits.
|
||||
* @param buffer
|
||||
* @param r
|
||||
* @param c
|
||||
* @param value
|
||||
* @param diagonalIndex
|
||||
* @returns
|
||||
*/
|
||||
private static propagateUpdateFrom<TUnit, TOpSet>(
|
||||
buffer: ClassicalDistanceCalculation<TUnit, TOpSet>,
|
||||
r: number,
|
||||
|
|
@ -772,16 +861,19 @@ export class ClassicalDistanceCalculation<
|
|||
}
|
||||
}
|
||||
|
||||
/* Is unused! */
|
||||
get mapKey(): string {
|
||||
let inputString = this.inputSequence.join('');
|
||||
let matchString = this.matchSequence.join('');
|
||||
return inputString + SENTINEL_CODE_UNIT + matchString + SENTINEL_CODE_UNIT + this.diagonalWidth;
|
||||
}
|
||||
|
||||
/* Is just a unit-test helper! */
|
||||
get lastInputEntry(): TUnit {
|
||||
return this.inputSequence[this.inputSequence.length-1];
|
||||
}
|
||||
|
||||
/* Is just a unit-test helper! */
|
||||
get lastMatchEntry(): TUnit {
|
||||
return this.matchSequence[this.matchSequence.length-1];
|
||||
}
|
||||
|
|
@ -842,6 +934,14 @@ export function forNewIndices<TUnit, TOpSet>(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the input and match indices specified, finds the closest viable parent
|
||||
* for a transposition, if one exists. If none exists, returns [-1, -1].
|
||||
* @param buffer
|
||||
* @param r
|
||||
* @param c
|
||||
* @returns
|
||||
*/
|
||||
function getTransposeParent<TUnit, TOpSet>(
|
||||
buffer: ClassicalDistanceCalculation<TUnit, TOpSet>,
|
||||
r: number,
|
||||
|
|
@ -873,6 +973,14 @@ function getTransposeParent<TUnit, TOpSet>(
|
|||
return [lastInputIndex, lastMatchIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the edit path used to determine when and where transposition edits
|
||||
* occur as part of the overall optimal cost. Designed for use with
|
||||
* `PathBuilder`.
|
||||
* @param pathBuilder
|
||||
* @param row
|
||||
* @param col
|
||||
*/
|
||||
export function findTransposeEdges<TUnit, TOpSet>(
|
||||
pathBuilder: PathBuilder<TUnit, TOpSet>,
|
||||
row: number,
|
||||
|
|
@ -937,6 +1045,12 @@ export function findTransposeEdges<TUnit, TOpSet>(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an edge-finding functor for use with the `PathBuilder` type. The
|
||||
* functor should determine the parent indices for any edits it supports,
|
||||
* calling the `.backtracePath` method on the `pathBuilder` parameter for each
|
||||
* along with metadata about the detected edit.
|
||||
*/
|
||||
type EdgeFinder<TUnit, TOpSet> = (
|
||||
pathBuilder: PathBuilder<TUnit, TOpSet>,
|
||||
row: number,
|
||||
|
|
@ -944,8 +1058,9 @@ type EdgeFinder<TUnit, TOpSet> = (
|
|||
) => void
|
||||
|
||||
/**
|
||||
* Determines the edit path used to obtain the optimal cost, distinguishing between zero-cost
|
||||
* substitutions ('match' operations) and actual substitutions.
|
||||
* Determines the edit path used to obtain the optimal cost, distinguishing
|
||||
* between zero-cost substitutions ('match' operations) and actual
|
||||
* substitutions. Designed for use with `PathBuilder`.
|
||||
* @param row
|
||||
* @param col
|
||||
*/
|
||||
|
|
@ -980,6 +1095,13 @@ export function findBaseEdges<TUnit, TOpSet>(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class designed to assist with determining the edit path for
|
||||
* edit-distance calculations based upon the `ClassicalDistanceCalculator` type.
|
||||
*
|
||||
* The types of expected edits may be configured at construction time and via
|
||||
* `addEdgeFinder`, restricting or extending the types of edits supported.
|
||||
*/
|
||||
export class PathBuilder<TUnit, TOpSet = EditOperation> {
|
||||
readonly calc: ClassicalDistanceCalculation<TUnit, TOpSet>;
|
||||
readonly edgeFinders: (EdgeFinder<TUnit, TOpSet>)[];
|
||||
|
|
@ -990,10 +1112,28 @@ export class PathBuilder<TUnit, TOpSet = EditOperation> {
|
|||
this.edgeFinders = edgeFinders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new edge-finding functor, allowing path-finding operations to
|
||||
* support additional edit operation types.
|
||||
* @param finder
|
||||
*/
|
||||
addEdgeFinder(finder: EdgeFinder<TUnit, TOpSet>) {
|
||||
this.edgeFinders.push(finder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the edit-operation sequences of mimimal cost that end at the
|
||||
* specified indices.
|
||||
*
|
||||
* The `recentEdge` parameter should provide metadata about the edit(s) used
|
||||
* to reach the specified indices. If no such edit(s) are required (say, at
|
||||
* the start point for determining paths), an empty array may be provided
|
||||
* instead.
|
||||
*
|
||||
* @param row
|
||||
* @param col
|
||||
* @param recentEdge
|
||||
*/
|
||||
backtracePath(row: number, col: number, recentEdge: EditTuple<TOpSet>[]) {
|
||||
const calc = this.calc;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue