/** * Copyright (C) 2013-2014 Olaf Lessenich * Copyright (C) 2014-2015 University of Passau, Germany * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * * Contributors: * Olaf Lessenich <lessenic@fim.uni-passau.de> * Georg Seibt <seibt@fim.uni-passau.de> */ package de.fosd.jdime.matcher.unordered.assignmentProblem; import java.util.ArrayList; import java.util.List; import de.fosd.jdime.artifact.Artifact; import de.fosd.jdime.matcher.MatcherInterface; import de.fosd.jdime.matcher.matching.Matching; import de.fosd.jdime.matcher.matching.Matchings; import de.fosd.jdime.util.Tuple; /** * This unordered matcher uses the hungarian algorithm to solve the assignment * problem. * * The implementation of the hungarian algorithm has been taken from * https://github.com/KevinStern/software-and-algorithms * which uses the MIT license. It implements the O(n^3) version of the * hungarian algorithm. * * @param <T> * type of artifact * @author Olaf Lessenich */ public class HungarianMatcher<T extends Artifact<T>> extends AssignmentProblemMatcher<T> { private static final String ID = HungarianMatcher.class.getSimpleName(); /** * Constructs a new <code>HungarianMatcher</code> using the given <code>matcher</code> for recursive calls. * * @param matcher * the parent <code>MatcherInterface</code> */ public HungarianMatcher(MatcherInterface<T> matcher) { super(matcher); } /** * {@inheritDoc} */ @Override protected Matchings<T> solveAssignmentProblem(T left, T right, Tuple<Integer, Matchings<T>>[][] childrenMatching, int rootMatching) { int m = childrenMatching.length; int n = childrenMatching[0].length; int[][] matrix = new int[m][n]; /* We want to solve the assignment problem for maximum values, * therefore we have to adjust the matrix by subtracting each value * from the maximum value. */ int max = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { matrix[i][j] = childrenMatching[i][j].x; if (matrix[i][j] > max) max = matrix[i][j]; } } for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[0].length; j++) { matrix[i][j] = max - matrix[i][j]; } } /* Solve via hungarian algorithm. */ HungarianAlgorithm alg = new HungarianAlgorithm(matrix); int[] bestMatches = alg.execute(); /* Build a list containing the relevant matches. */ List<Matchings<T>> children = new ArrayList<>(); int score = 0; for (int i = 0; i < bestMatches.length; i++) { int j = bestMatches[i]; if (j < 0) continue; Tuple<Integer, Matchings<T>> curMatching = childrenMatching[i][j]; if (curMatching.x > 0) { children.add(curMatching.y); score += curMatching.x; } } Matching<T> matching = new Matching<>(left, right, score + rootMatching); matching.setAlgorithm(ID); Matchings<T> result = new Matchings<>(); result.add(matching); result.addAllMatchings(children); return result; } }