/**********
This file is part of levenshpp.
levenshpp is free library: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
levenshpp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with levenshpp. If not, see .
**********/
#pragma once
#include
#include
#include
template
class LevenshteinPotencial
{
public:
LevenshteinPotencial(const T &px, const T &py, const T value): coords(std::pair(px, py)), minValue(value)
{ }
unsigned int getTaxiCab() const
{
return coords.first +coords.second;
}
bool operator<(const LevenshteinPotencial &o) const
{
if (minValue == o.minValue)
return getTaxiCab() > o.getTaxiCab(); // The bigger the best
return minValue < o.minValue;
}
bool operator==(const std::pair &o) const
{
return coords.first == o.first && coords.second == o.second;
}
std::pair coords;
T minValue;
};
static int levenshtein_get(int **map, int px, int py)
{
if (px == -1 && py == -1)
return 0;
if (px == -1)
return py +1;
if (py == -1)
return px +1;
return map[px][py];
}
template
unsigned int levenshtein(const T &a, const T &b, const SIZE aSize, const SIZE bSize)
{
int **items = new int*[aSize]();
std::multiset > toProcess;
for (SIZE i =0; i < aSize; i++)
{
items[i] = new int[bSize]();
toProcess.insert(LevenshteinPotencial(0, i, i));
for (SIZE j=0; j < bSize; j++)
items[i][j] = -1;
}
for (SIZE i =1; i < bSize; i++)
toProcess.insert(LevenshteinPotencial(i, 0, i));
while (toProcess.size())
{
const auto currentIt = toProcess.cbegin();
const LevenshteinPotencial ¤t = *(currentIt);
int add = levenshtein_get(items, current.coords.first -1, current.coords.second);
int rem = levenshtein_get(items, current.coords.first, current.coords.second -1);
int mod = levenshtein_get(items, current.coords.first -1, current.coords.second -1);
int min = -1;
// Compute weight
if (add != -1)
min = add +1;
if (rem != -1)
min = min == -1 ? rem +1 : std::min(min, rem +1);
if (mod != -1)
{
if (a[current.coords.first] != b[current.coords.second])
mod++;
min = min == -1 ? mod : std::min(min, mod);
}
items[current.coords.first][current.coords.second] = min;
if (current.coords.first == aSize -1 && current.coords.second == bSize -1)
break;
//update toProcess
add = rem = mod = -1;
for (auto i = toProcess.cbegin(); i != toProcess.cend(); i++)
{
if (*i == std::pair(current.coords.first, current.coords.second +1))
{
add = (*i).minValue;
toProcess.erase(i);
}
else if (*i == std::pair(current.coords.first +1, current.coords.second))
{
rem = (*i).minValue;
toProcess.erase(i);
}
else if (*i == std::pair(current.coords.first +1, current.coords.second +1))
{
mod = (*i).minValue;
toProcess.erase(i);
}
}
if (current.coords.second +1 < bSize && items[current.coords.first][current.coords.second +1] == -1)
toProcess.insert(LevenshteinPotencial(current.coords.first, current.coords.second +1, add == -1 ? min +1 : std::min(min +1, add)));
if (current.coords.first +1 < aSize && items[current.coords.first +1][current.coords.second] == -1)
toProcess.insert(LevenshteinPotencial(current.coords.first +1, current.coords.second, rem == -1 ? min +1 : std::min(min +1, rem)));
if (current.coords.first +1 < aSize && current.coords.second +1 < bSize &&
items[current.coords.first +1][current.coords.second +1] == -1)
toProcess.insert(LevenshteinPotencial(current.coords.first +1, current.coords.second +1, mod == -1 ? min : std::min(mod, min)));
toProcess.erase(currentIt);
}
const unsigned int levenshtein = items[aSize -1][bSize -1];
for (SIZE i =0; i < aSize; i++)
delete[] items[i];
delete[] items;
return levenshtein;
}