@a-s8h/liblevenshtein
Version:
Various utilities regarding Levenshtein transducers.
142 lines (120 loc) • 4.67 kB
JavaScript
// Generated by CoffeeScript 1.7.1
/**
* The algorithm for imitating Levenshtein automata was taken from the
* following journal article:
*
* @ARTICLE{Schulz02faststring,
* author = {Klaus Schulz and Stoyan Mihov},
* title = {Fast String Correction with Levenshtein-Automata},
* journal = {INTERNATIONAL JOURNAL OF DOCUMENT ANALYSIS AND RECOGNITION},
* year = {2002},
* volume = {5},
* pages = {67--85}
* }
*
* As well, this Master Thesis helped me understand its concepts:
*
* www.fmi.uni-sofia.bg/fmi/logic/theses/mitankin-en.pdf
*
* The supervisor of the student who submitted the thesis was one of the
* authors of the journal article, above.
*
* The algorithm for constructing a DAWG (Direct Acyclic Word Graph) from the
* input dictionary of words (DAWGs are otherwise known as an MA-FSA, or
* Minimal Acyclic Finite-State Automata), was taken and modified from the
* following blog from Steve Hanov:
*
* http://stevehanov.ca/blog/index.php?id=115
*
* The algorithm therein was taken from the following paper:
*
* @MISC{Daciuk00incrementalconstruction,
* author = {Jan Daciuk and Bruce W. Watson and Richard E. Watson and Stoyan Mihov},
* title = {Incremental Construction of Minimal Acyclic Finite-State Automata},
* year = {2000}
* }
*/
(function() {
var Transducer, global,
__hasProp = {}.hasOwnProperty;
Transducer = (function() {
Transducer.prototype['minimum_distance'] = function(state, w) {
throw new Error('minimum_distance not specified on construction');
};
Transducer.prototype['build_matches'] = function() {
throw new Error('build_matches not specified on construction');
};
Transducer.prototype['initial_state'] = function() {
throw new Error('initial_state not specified on construction');
};
Transducer.prototype['root'] = function() {
throw new Error('root not specified on construction');
};
Transducer.prototype['edges'] = function(q_D) {
throw new Error('edges not specified on construction');
};
Transducer.prototype['is_final'] = function(q_D) {
throw new Error('is_final not specified on construction');
};
Transducer.prototype['transform'] = function(matches) {
throw new Error('transform not specified on construction');
};
Transducer.prototype['transition_for_state'] = function(n) {
throw new Error('transition_for_state not specified on construction');
};
Transducer.prototype['characteristic_vector'] = function(x, term, k, i) {
throw new Error('characteristic_vector not specified on construction');
};
Transducer.prototype['push'] = function(matches, candidate) {
throw new Error('push not specified on construction');
};
Transducer.prototype['default_edit_distance'] = function() {
throw new Error('default_edit_distance not specified on construction');
};
function Transducer(attributes) {
var attribute;
for (attribute in attributes) {
if (!__hasProp.call(attributes, attribute)) continue;
this[attribute] = attributes[attribute];
}
}
Transducer.prototype['transduce'] = function(term, n) {
var M, V, a, b, distance, i, k, matches, next_M, next_V, next_q_D, q_D, stack, transition, vector, w, x, _ref, _ref1;
if (typeof n !== 'number') {
n = this['default_edit_distance']();
}
w = term.length;
transition = this['transition_for_state'](n);
matches = this['build_matches']();
stack = [['', this['root'](), this['initial_state']()]];
while (stack.length > 0) {
_ref = stack['pop'](), V = _ref[0], q_D = _ref[1], M = _ref[2];
i = M[0][0];
a = 2 * n + 1;
b = w - i;
k = a < b ? a : b;
_ref1 = this['edges'](q_D);
for (x in _ref1) {
next_q_D = _ref1[x];
vector = this['characteristic_vector'](x, term, k, i);
next_M = transition(M, vector);
if (next_M) {
next_V = V + x;
stack.push([next_V, next_q_D, next_M]);
if (this['is_final'](next_q_D)) {
distance = this['minimum_distance'](next_M, w);
if (distance <= n) {
this['push'](matches, [next_V, distance]);
}
}
}
}
}
return this['transform'](matches);
};
return Transducer;
})();
global = typeof exports === 'object' ? exports : typeof window === 'object' ? window : this;
global['levenshtein'] || (global['levenshtein'] = {});
global['levenshtein']['Transducer'] = Transducer;
}).call(this);