8#include <rapidfuzz/details/GrowingHashmap.hpp>
9#include <rapidfuzz/details/Matrix.hpp>
10#include <rapidfuzz/details/Range.hpp>
11#include <rapidfuzz/details/common.hpp>
12#include <rapidfuzz/details/distance.hpp>
17template <
typename IntType>
20 friend bool operator==(
const RowId& lhs,
const RowId& rhs)
22 return lhs.val == rhs.val;
25 friend bool operator!=(
const RowId& lhs,
const RowId& rhs)
36template <
typename IntType,
typename InputIt1,
typename InputIt2>
37size_t damerau_levenshtein_distance_zhao(
const Range<InputIt1>& s1,
const Range<InputIt2>& s2,
size_t max)
40 IntType len1 =
static_cast<IntType
>(s1.size());
41 IntType len2 =
static_cast<IntType
>(s2.size());
42 IntType maxVal =
static_cast<IntType
>(std::max(len1, len2) + 1);
43 assert(std::numeric_limits<IntType>::max() > maxVal);
45 HybridGrowingHashmap<typename Range<InputIt1>::value_type, RowId<IntType>> last_row_id;
46 size_t size = s2.size() + 2;
48 std::vector<IntType> FR_arr(size, maxVal);
49 std::vector<IntType> R1_arr(size, maxVal);
50 std::vector<IntType> R_arr(size);
52 std::iota(R_arr.begin() + 1, R_arr.end(), IntType(0));
54 IntType* R = &R_arr[1];
55 IntType* R1 = &R1_arr[1];
56 IntType* FR = &FR_arr[1];
58 auto iter_s1 = s1.begin();
59 for (IntType i = 1; i <= len1; i++) {
61 IntType last_col_id = -1;
62 IntType last_i2l1 = R[0];
66 auto iter_s2 = s2.begin();
67 for (IntType j = 1; j <= len2; j++) {
68 int64_t diag = R1[j - 1] +
static_cast<IntType
>(*iter_s1 != *iter_s2);
69 int64_t left = R[j - 1] + 1;
70 int64_t up = R1[j] + 1;
71 int64_t temp = std::min({diag, left, up});
73 if (*iter_s1 == *iter_s2) {
79 int64_t k = last_row_id.get(
static_cast<uint64_t
>(*iter_s2)).val;
80 int64_t l = last_col_id;
83 int64_t transpose = FR[j] + (i - k);
84 temp = std::min(temp, transpose);
86 else if ((i - k) == 1) {
87 int64_t transpose = T + (j - l);
88 temp = std::min(temp, transpose);
93 R[j] =
static_cast<IntType
>(temp);
96 last_row_id[*iter_s1].val = i;
100 size_t dist =
static_cast<size_t>(R[s2.size()]);
101 return (dist <= max) ? dist : max + 1;
104template <
typename InputIt1,
typename InputIt2>
105size_t damerau_levenshtein_distance(Range<InputIt1> s1, Range<InputIt2> s2,
size_t max)
107 size_t min_edits = abs_diff(s1.size(), s2.size());
108 if (min_edits > max)
return max + 1;
111 remove_common_affix(s1, s2);
113 size_t maxVal = std::max(s1.size(), s2.size()) + 1;
114 if (std::numeric_limits<int16_t>::max() > maxVal)
115 return damerau_levenshtein_distance_zhao<int16_t>(s1, s2, max);
116 else if (std::numeric_limits<int32_t>::max() > maxVal)
117 return damerau_levenshtein_distance_zhao<int32_t>(s1, s2, max);
119 return damerau_levenshtein_distance_zhao<int64_t>(s1, s2, max);
122class DamerauLevenshtein
123 :
public DistanceBase<DamerauLevenshtein, size_t, 0, std::numeric_limits<int64_t>::max()> {
124 friend DistanceBase<DamerauLevenshtein, size_t, 0, std::numeric_limits<int64_t>::max()>;
125 friend NormalizedMetricBase<DamerauLevenshtein>;
127 template <
typename InputIt1,
typename InputIt2>
128 static size_t maximum(
const Range<InputIt1>& s1,
const Range<InputIt2>& s2)
130 return std::max(s1.size(), s2.size());
133 template <
typename InputIt1,
typename InputIt2>
134 static size_t _distance(
const Range<InputIt1>& s1,
const Range<InputIt2>& s2,
size_t score_cutoff,
size_t)
136 return damerau_levenshtein_distance(s1, s2, score_cutoff);