/** * edu.utexas.GeDBIT.dist.MSMetric 2004.03.17 * * Copyright Information: * * Change Log: * 2004.05.31; Modified for performance, replaced ArrayLists with arrays, by Willard * 2004.08.02; Modified to implement MSDataConstants, by Smriti Ramakrishnan */ package GeDBIT.dist; import GeDBIT.dist.Metric; import GeDBIT.type.DoubleVector; import GeDBIT.type.IndexObject; import GeDBIT.type.SpectraWithPrecursorMass; import static GeDBIT.dist.MSMSConstants.*; /** * MSMSMetric is an implementation of a fuzzy cosine distance metric for * comparing tandem spectra signatures. Elements of the vectors are equal, * within a given tolerance. * * @author Smriti Ramakrishnan, Willard * @version 2004.11.29 */ public class MSMSMetric implements Metric { public MSMSMetric(int min, int max, double step, double tol) { // super(min, max, step); this.min = min; this.max = max; this.step = step; this.tol = tol; mscosdist = 0.0; absMassDiff = 0.0; massDiffTerm = 0.0; } /** * default constructor provides default values for min, max, step, tolerance * min = 0; max = 0; step = 0; tol = MSMSConstants.MS_TOLERANCE */ public MSMSMetric() { this.min = 0; this.max = 0; this.step = 0; this.tol = MS_TOLERANCE; mscosdist = 0.0; absMassDiff = 0.0; massDiffTerm = 0.0; } /** * @param v1 * the {@link IndexObject} over which the keys are defined. * @param v2 * the other {@link IndexObject} over which the keys are defined. */ public double getDistance(IndexObject v1, IndexObject v2) { return getDistance((SpectraWithPrecursorMass) v1, (SpectraWithPrecursorMass) v2); } /** * @param v1 * the {@link SpectraWithPrecursorMass} over which the keys are * defined. * @param v2 * the other {@link SpectraWithPrecursorMass} over which the keys * are defined. */ public double getDistance(SpectraWithPrecursorMass v1, SpectraWithPrecursorMass v2) { // now compute cosine distance double cos = getCosine(v1, v2); // from BinaryVectorMetric:getDistance() // if ( Math.abs(cos) > 1) {; Smriti if (Math.abs(Math.abs(cos) - 1) < COS_THRESHOLD) { // precision if (cos > 0) cos = 1; // very similar else cos = -1; // very unsimilar } else if (Math.abs(cos) > 1) { System.out.println("COS_THRESHOLD = " + COS_THRESHOLD + ", cos = " + cos); System.out.println("got cosine > 1, cosine=" + cos + ", :" + v1.toString() + ", v2:" + v2.toString() + "Quitting."); System.exit(0); } // } /* * System.out.println("MSTOL = " + tol); System.out.println("MSTOL = " + * MS_PRECURSOR_TOLERANCE); System.out.println("MSDKO-1 : " + v1); * System.out.println("MSDKO-2 : " + v2); */ // ******************************************** mscosdist = Math.acos(cos); massDiffTerm = getAbsPrecursorMassDiff(v1, v2); double dist = massDiffTerm + mscosdist; // ******************************************** /* * System.out.println("K1 = " + v1); System.out.println("K2 = " + v2); * System.out.println("mscosDist = " + mscosdist + ", Cosine = " + cos + * ", MassDiff = " + massDiff); System.out.println("Total Dist = " + * dist); System.out.println(); */ return dist; // smriti - 30 sep // return (1 - cos); /* * //extended jaccard double[] one = v1.getData(); double[] two = * v2.getData(); double spc = getInnerProduct(one, two); double dist = 1 * - (spc / (getMagnitude(one) + getMagnitude(two) - spc)); return dist; */ // getCosine(,v2));//weijia } /** * Returns absolute difference between precursor masses - within a tolerance */ private double getAbsPrecursorMassDiff(SpectraWithPrecursorMass v1, SpectraWithPrecursorMass v2) { double m1 = v1.getPrecursorMass(); double m2 = v2.getPrecursorMass(); absMassDiff = Math.abs(m1 - m2); if (absMassDiff < COS_THRESHOLD) absMassDiff = 0.0; if (absMassDiff <= MS_PRECURSOR_TOLERANCE) return 0.0; else return (absMassDiff); } /** * @param one * @param two * @return */ private double getCosine(DoubleVector one, DoubleVector two) { double[] v1 = one.getData(); double[] v2 = two.getData(); return getInnerProduct(v1, v2) / (getMagnitude(v1) * getMagnitude(v2)); // smriti - 30sep /* * double numer = getInnerProduct(v1, v2) ; double denom = * getMagnitude(v1) * getMagnitude(v2); double denom = getMagnitude(v1) * * getMagnitude(v1); double d2 = getMagnitude(v2) * getMagnitude(v2); * denom = (denom + d2) / 2; return numer/denom; */ } /** * Computes inner product within a certain tolerance-- "fuzzy" inner * product. */ private int getInnerProduct(double[] v1, double[] v2) { int dist = 0; int i = 0, j = 0; double val1; double val2; // System.out.println("TOL = " + tol); while (i < v1.length && j < v2.length) { val1 = v1[i]; val2 = v2[j]; // new version -- gets rid of Math.abs() if (val1 <= val2) { if (val2 - val1 <= tol) { dist++; i++; j++; } else { i++; } } else { if (val1 - val2 <= tol) { dist++; i++; j++; } else { j++; } } /* * old code if (Math.abs(val1 - val2) <= tol) { dist++; i++; j++; } * else { if (val1 < val2) i++; else j++; } */ // debug // System.out.println("i = " + i + ", j = " + j); } // System.out.println("INNER PROD = " + dist); return dist; } /** * For experiment purpose only Method to compute inner product, cosine value * and distance of v2 {@link VectorData} objects by treating them as binary * vectors in a multidimensional space.The Value will be stored in a {@link * double[]} with the correspoding order. * * @param - {@link VectorData} * @param v2 * - {@link vectorData} * @return {@link double []} */ /* * public double[] getAll(DataVector one, DataVector two) { double[] v1 = * one.getData(); double[] v2 = two.getData(); double[] result = new * double[3]; result[0] = getInnerProduct(v1, v2); result[1] = result[0] / * (getMagnitude(v1) * getMagnitude(v2)); result[2] = Math.(result[1]); * return result; } */ /** * @param {@link VectorData} */ /** * Computes the magnitude of the double array by treating it as a *sparse* * binary vector (store only 1's) * * @param d * @return */ private double getMagnitude(double[] d) { return Math.sqrt(d.length); // return d.length; } /** * Convert information of the instance into a {@link String} that contains * the number of dimension and meaning for each dimension */ public String printDistance(SpectraWithPrecursorMass k1, SpectraWithPrecursorMass k2) { // set values of mscosdist and massDiff getDistance(k1, k2); java.text.DecimalFormat frm = new java.text.DecimalFormat( "####.########"); StringBuffer outStr = new StringBuffer(20); // outStr.append("k1: " + k1); // outStr.append("k2: " + k2 + "\n"); outStr.append("MSCOSDIST = " + frm.format(mscosdist) + ", MASS_DIFF_TERM = " + frm.format(massDiffTerm) + " (abs mass diff = " + frm.format(absMassDiff) + ")\n"); return outStr.toString(); } // legacy int min, max; // min, max are mass ranges double step; // Same as Tolerance ? // end-legacy double mscosdist; double absMassDiff; double massDiffTerm; double tol; private final double COS_THRESHOLD = 0.00005; static final long serialVersionUID = 8368326281379099335L; }