RapidFuzz
Loading...
Searching...
No Matches
JaroWinkler_impl.hpp
1/* SPDX-License-Identifier: MIT */
2/* Copyright © 2022-present Max Bachmann */
3
4#include <rapidfuzz/distance/Jaro.hpp>
5
6namespace rapidfuzz {
7namespace detail {
8
9template <typename InputIt1, typename InputIt2>
10double jaro_winkler_similarity(const Range<InputIt1>& P, const Range<InputIt2>& T, double prefix_weight,
11 double score_cutoff)
12{
13 size_t P_len = P.size();
14 size_t T_len = T.size();
15 size_t min_len = std::min(P_len, T_len);
16 size_t prefix = 0;
17 size_t max_prefix = std::min(min_len, size_t(4));
18
19 for (; prefix < max_prefix; ++prefix)
20 if (T[prefix] != P[prefix]) break;
21
22 double jaro_score_cutoff = score_cutoff;
23 if (jaro_score_cutoff > 0.7) {
24 double prefix_sim = static_cast<double>(prefix) * prefix_weight;
25
26 if (prefix_sim >= 1.0)
27 jaro_score_cutoff = 0.7;
28 else
29 jaro_score_cutoff = std::max(0.7, (prefix_sim - jaro_score_cutoff) / (prefix_sim - 1.0));
30 }
31
32 double Sim = jaro_similarity(P, T, jaro_score_cutoff);
33 if (Sim > 0.7) {
34 Sim += static_cast<double>(prefix) * prefix_weight * (1.0 - Sim);
35 Sim = std::min(Sim, 1.0);
36 }
37
38 return (Sim >= score_cutoff) ? Sim : 0;
39}
40
41template <typename InputIt1, typename InputIt2>
42double jaro_winkler_similarity(const BlockPatternMatchVector& PM, const Range<InputIt1>& P,
43 const Range<InputIt2>& T, double prefix_weight, double score_cutoff)
44{
45 size_t P_len = P.size();
46 size_t T_len = T.size();
47 size_t min_len = std::min(P_len, T_len);
48 size_t prefix = 0;
49 size_t max_prefix = std::min(min_len, size_t(4));
50
51 for (; prefix < max_prefix; ++prefix)
52 if (T[prefix] != P[prefix]) break;
53
54 double jaro_score_cutoff = score_cutoff;
55 if (jaro_score_cutoff > 0.7) {
56 double prefix_sim = static_cast<double>(prefix) * prefix_weight;
57
58 if (prefix_sim >= 1.0)
59 jaro_score_cutoff = 0.7;
60 else
61 jaro_score_cutoff = std::max(0.7, (prefix_sim - jaro_score_cutoff) / (prefix_sim - 1.0));
62 }
63
64 double Sim = jaro_similarity(PM, P, T, jaro_score_cutoff);
65 if (Sim > 0.7) {
66 Sim += static_cast<double>(prefix) * prefix_weight * (1.0 - Sim);
67 Sim = std::min(Sim, 1.0);
68 }
69
70 return (Sim >= score_cutoff) ? Sim : 0;
71}
72
73class JaroWinkler : public SimilarityBase<JaroWinkler, double, 0, 1, double> {
74 friend SimilarityBase<JaroWinkler, double, 0, 1, double>;
75 friend NormalizedMetricBase<JaroWinkler, double>;
76
77 template <typename InputIt1, typename InputIt2>
78 static double maximum(const Range<InputIt1>&, const Range<InputIt2>&, double) noexcept
79 {
80 return 1.0;
81 }
82
83 template <typename InputIt1, typename InputIt2>
84 static double _similarity(const Range<InputIt1>& s1, const Range<InputIt2>& s2, double prefix_weight,
85 double score_cutoff, double)
86 {
87 return jaro_winkler_similarity(s1, s2, prefix_weight, score_cutoff);
88 }
89};
90
91} // namespace detail
92} // namespace rapidfuzz