package GeDBIT.dist; /** * mobios.dist.EditDistance, 2011.07.21 * * Copyright Information: * * Change Log: * 2011.07.21: Modified from http://www.merriampark.com/ld.htm#FLAVORS, by Rui Mao. */ import GeDBIT.dist.Metric; import GeDBIT.type.IndexObject; import GeDBIT.type.StringObject; /** * This class computes edit distance between two {@link String}s. Insert and * delete cost are considered to be the same, called gap cost. * * @author Rui Mao * @version 2011.07.21 */ public class EditDistance implements Metric { final int gapCost; final int substitutionCost; private static final long serialVersionUID = -4658067077491099474L; /** * Default constructor, gap cost (insert/delete cost) =1, substitution cost * =1; */ public EditDistance() { this(1, 1); } /** * Constructor, the two arguments should satisfy gapCost/2 <= * substitutionCost <= gapCost *2 * * @param gapCost * insert/delete cost * @param substitutionCost * substitution cost. */ public EditDistance(int gapCost, int substitutionCost) { if ((gapCost > substitutionCost * 2) || (substitutionCost > gapCost * 2)) throw new IllegalArgumentException( "the two arguments should satisfy gapCost/2 <= substitutionCost <= gapCost *2!"); this.gapCost = gapCost; this.substitutionCost = substitutionCost; } // **************************** // Get minimum of three values // **************************** private int minimum(int a, int b, int c) { int min = (a <= b) ? a : b; return (min <= c) ? min : c; } /** * Computes the distance, the two arguments should be of type {@link String} */ public double getDistance(Object one, Object two) { if (one == null) throw new IllegalArgumentException( "the first object to compute distance is null!"); if (two == null) throw new IllegalArgumentException( "the second object to compute distance is null!"); return getDistance((String) one, (String) two); } public double getDistance(IndexObject one, IndexObject two) { if (one == null) throw new IllegalArgumentException( "the first object to compute distance is null!"); if (two == null) throw new IllegalArgumentException( "the second object to compute distance is null!"); return getDistance((StringObject) one, (StringObject) two); } /** * Computes the distance between two {@link String}s * * @param first * the first String to compute edit distance * @param second * the second String to compute edit distance * @return the edit distance between the two arguments */ public double getDistance(StringObject first, StringObject second) { return getDistance(first.getData(), second.getData()); } public double getDistance(String first, String second) { int matrix[][]; // the dynamic programming matrix final int firstSize = first.length(); // length of first final int secondSize = second.length(); // length of second // Step 1 if (firstSize == 0) return secondSize * gapCost; if (secondSize == 0) return firstSize * gapCost; matrix = new int[firstSize + 1][secondSize + 1]; // Step 2, initialize the matrix( first row and first column) for (int i = 0; i <= firstSize; i++) matrix[i][0] = i * gapCost; for (int j = 0; j <= secondSize; j++) matrix[0][j] = j * gapCost; // Step 3, fill the matrix char firstChar; int j; int cost; for (int i = 1; i <= firstSize; i++) { firstChar = first.charAt(i - 1); for (j = 1; j <= secondSize; j++) { cost = (firstChar == second.charAt(j - 1)) ? 0 : substitutionCost; matrix[i][j] = minimum(matrix[i - 1][j] + gapCost, matrix[i][j - 1] + gapCost, matrix[i - 1][j - 1] + cost); } } return matrix[firstSize][secondSize]; } /** * main method, for test purpose. * * @param args */ public static void main(String[] args) { System.out.print("EditDistance(\"" + args[0] + "\", \"" + args[1] + "\" ) = "); EditDistance metric = new EditDistance(); System.out.println(metric.getDistance(args[0], args[1])); } }