#pragma once #include #include #include "jsonContainer.hh" #include "levenshtein.hpp" #include "outputFlag.hh" class LevenshteinMatrice_base { public: virtual ~LevenshteinMatrice_base() {} virtual const std::map path() const; virtual size_t result() const =0; virtual bool areSimilar() const =0; eLevenshteinOperator get(const JSonElement *) const; virtual std::map getEquivalences() const; virtual const JSonElement * getEquivalence(const JSonElement *) const; public: class Builder { public: Builder(); ~Builder(); LevenshteinMatrice_base *build(const JSonElement *a, const JSonElement *b) const; }; protected: std::map operations; }; class LevenshteinMatrice_manual: public LevenshteinMatrice_base { public: LevenshteinMatrice_manual *add(const JSonElement*, eLevenshteinOperator); size_t result() const; bool areSimilar() const; public: size_t _result; }; class LevenshteinMatriceWithScore: public LevenshteinMatrice_base { public: LevenshteinMatriceWithScore(float score, const JSonElement *a, const JSonElement *b, bool sameType); std::map getEquivalences() const; virtual const JSonElement * getEquivalence(const JSonElement *) const; size_t result() const; bool areSimilar() const; private: bool _result; const JSonElement *equivalentA, *equivalentB; }; class LevenshteinMatrice: public LevenshteinMatrice_base { public: template static LevenshteinMatrice *build(const JSonContainer::const_iterator aBegin, const JSonContainer::const_iterator bBegin, const size_t n, const size_t m) { LevenshteinMatrice *result = new LevenshteinMatrice(); size_t i, j; JSonContainer::const_iterator a = aBegin; JSonContainer::const_iterator b; LevenshteinMatrice_base::Builder matriceBuilder; T **matrice = new T*[n +1](); LevenshteinMatrice_base ***subMatrice = new LevenshteinMatrice_base**[n](); matrice[0] = new T[m +1]; for (i =0; i <= m; ++i) matrice[0][i] = i; for (i=1; i <= n; ++i) { matrice[i] = new T[m +1]; matrice[i][0] = i; subMatrice[i -1] = new LevenshteinMatrice_base*[m]; for (size_t j=0; j < m; ++j) subMatrice[i -1][j] = nullptr; } for (i =1; i <= n; ++i, ++a) { b = bBegin; for (j =1; j <= m; ++j, ++b) { LevenshteinMatrice_base *_subMatrice = matriceBuilder.build(*a, *b); if (_subMatrice != nullptr) { const T chCost = matrice[i -1][j -1] + (_subMatrice->areSimilar() ? 0 : _subMatrice->result()); if (chCost <= matrice[i -1][j] +1 && chCost <= matrice[i][j -1] +1) { matrice[i][j] = chCost; subMatrice[i -1][j -1] = _subMatrice; continue; } delete _subMatrice; } // Change is not worth, consider adding/removing matrice[i][j] = std::min(matrice[i -1][j], matrice[i][j -1]) +1; } } result->levenDist = matrice[n][m]; result->levenRelativeDist = 1 -(matrice[n][m] / std::max(n, m)); if (result->levenRelativeDist > LEVENSHTEIN_SENSIBILITY) result->shortestPath(matrice, subMatrice, n, m, --a, --b); cleanMatrice(matrice, subMatrice, n, m); return result; }; template static void cleanMatrice(T **matrice, LevenshteinMatrice_base ***subMatrice, const size_t &n, const size_t &m) { for (size_t i=0; i <= n; ++i) { delete []matrice[i]; if (i != n) { for (size_t j=0; j < m; ++j) if (subMatrice[i][j]) delete subMatrice[i][j]; delete []subMatrice[i]; } } delete []matrice; delete []subMatrice; }; void addRoot(const JSonContainer *a, const JSonContainer *b) { if (levenRelativeDist < LEVENSHTEIN_SENSIBILITY) { operations[a] = eLevenshteinOperator::add; operations[b] = eLevenshteinOperator::add; } else { operations[a] = operations[b] = levenRelativeDist < 1.f ? eLevenshteinOperator::mod : eLevenshteinOperator::equ; equivalences[a] = b; equivalences[b] = a; } } std::map getEquivalences() const; size_t result() const; bool areSimilar() const; const JSonElement *getEquivalence(const JSonElement *) const; private: template void shortestPath(T **matrice, LevenshteinMatrice_base ***subMatrice, size_t _i, size_t _j, JSonContainer::const_iterator i, JSonContainer::const_iterator j) { while (_i || _j) { if (_i && (!_j || matrice[_i][_j] > matrice[_i-1][_j])) { operations[*i] = eLevenshteinOperator::add; --i; --_i; } else if (_j && (!_i || matrice[_i][_j] > matrice[_i][_j -1])) { operations[*j] = eLevenshteinOperator::add; --j; --_j; } else if (_i && _j) { eLevenshteinOperator op = matrice[_i][_j] == matrice[_i -1][_j -1] ? eLevenshteinOperator::equ : eLevenshteinOperator::mod; operations[*i] = operations[*j] = op; for (std::pair e : subMatrice[_i -1][_j -1]->path()) operations[e.first] = e.second; for (std::pair e : (subMatrice[_i -1][_j -1])->getEquivalences()) equivalences[e.first] = e.second; equivalences[*i] = *j; --i; --j; --_i; --_j; } else if (_i) { operations[*i] = eLevenshteinOperator::add; --i; --_i; } else if (_j) { operations[*j] = eLevenshteinOperator::add; --j; --_j; } } } private: LevenshteinMatrice(); size_t levenDist; float levenRelativeDist; std::map equivalences; };