From 69b81735359f0d9b72603cb3151c2ef6267d4b57 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Wed, 27 Feb 2013 14:01:09 -0500 Subject: [PATCH] Replace uses of NestedHashMap with NestedIntegerArray. * Removed from codebase NestedHashMap since it is unused and untested. * Integration tests change because the BQSR CSV is now sorted automatically. * Resolves GSA-732 --- .../sting/utils/recalibration/RecalUtils.java | 70 +++++++--- .../walkers/bqsr/BQSRIntegrationTest.java | 2 +- .../utils/collections/NestedHashMap.java | 132 ------------------ 3 files changed, 50 insertions(+), 154 deletions(-) delete mode 100644 public/java/src/org/broadinstitute/sting/utils/collections/NestedHashMap.java diff --git a/protected/java/src/org/broadinstitute/sting/utils/recalibration/RecalUtils.java b/protected/java/src/org/broadinstitute/sting/utils/recalibration/RecalUtils.java index 6d98803c9..ce2869e94 100644 --- a/protected/java/src/org/broadinstitute/sting/utils/recalibration/RecalUtils.java +++ b/protected/java/src/org/broadinstitute/sting/utils/recalibration/RecalUtils.java @@ -46,6 +46,8 @@ package org.broadinstitute.sting.utils.recalibration; +import com.google.java.contract.Ensures; +import com.google.java.contract.Requires; import net.sf.samtools.SAMFileHeader; import org.apache.log4j.Logger; import org.broadinstitute.sting.gatk.report.GATKReport; @@ -59,7 +61,6 @@ import org.broadinstitute.sting.utils.R.RScriptExecutor; import org.broadinstitute.sting.utils.Utils; import org.broadinstitute.sting.utils.classloader.PluginManager; import org.broadinstitute.sting.utils.collections.NestedIntegerArray; -import org.broadinstitute.sting.utils.collections.NestedHashMap; import org.broadinstitute.sting.utils.collections.Pair; import org.broadinstitute.sting.utils.exceptions.DynamicClassResolutionException; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; @@ -423,7 +424,7 @@ public class RecalUtils { private static void writeCSV(final PrintStream deltaTableFile, final RecalibrationTables recalibrationTables, final String recalibrationMode, final Covariate[] requestedCovariates, final boolean printHeader) { - final NestedHashMap deltaTable = new NestedHashMap(); + final NestedIntegerArray deltaTable = createDeltaTable(recalibrationTables, requestedCovariates.length); // add the quality score table to the delta table final NestedIntegerArray qualTable = recalibrationTables.getQualityScoreTable(); @@ -470,24 +471,57 @@ public class RecalUtils { covariateNameMap.put(covariate, parseCovariateName(covariate)); // print each data line - for (final NestedHashMap.Leaf leaf : deltaTable.getAllLeaves()) { + for (final NestedIntegerArray.Leaf leaf : deltaTable.getAllLeaves()) { final List deltaKeys = generateValuesFromKeys(leaf.keys, requestedCovariates, covariateNameMap); - final RecalDatum deltaDatum = (RecalDatum)leaf.value; + final RecalDatum deltaDatum = leaf.value; deltaTableFile.print(Utils.join(",", deltaKeys)); deltaTableFile.print("," + deltaDatum.stringForCSV()); deltaTableFile.println("," + recalibrationMode); } } - protected static List generateValuesFromKeys(final List keys, final Covariate[] covariates, final Map covariateNameMap) { + /* + * Return an initialized nested integer array with appropriate dimensions for use with the delta tables + * + * @param recalibrationTables the recal tables + * @param numCovariates the total number of covariates being used + * @return a non-null nested integer array + */ + @Requires("recalibrationTables != null && numCovariates > 0") + @Ensures("result != null") + private static NestedIntegerArray createDeltaTable(final RecalibrationTables recalibrationTables, final int numCovariates) { + + final int[] dimensionsForDeltaTable = new int[4]; + + // initialize the dimensions with those of the qual table to start with + final NestedIntegerArray qualTable = recalibrationTables.getQualityScoreTable(); + final int[] dimensionsOfQualTable = qualTable.getDimensions(); + dimensionsForDeltaTable[0] = dimensionsOfQualTable[0]; // num read groups + dimensionsForDeltaTable[1] = numCovariates + 1; // num covariates + dimensionsForDeltaTable[2] = dimensionsOfQualTable[1]; + dimensionsForDeltaTable[3] = dimensionsOfQualTable[2]; + + // now, update the dimensions based on the optional covariate tables as needed + for ( int i = RecalibrationTables.TableType.OPTIONAL_COVARIATE_TABLES_START.ordinal(); i < numCovariates; i++ ) { + final NestedIntegerArray covTable = recalibrationTables.getTable(i); + final int[] dimensionsOfCovTable = covTable.getDimensions(); + dimensionsForDeltaTable[2] = Math.max(dimensionsForDeltaTable[2], dimensionsOfCovTable[2]); + dimensionsForDeltaTable[3] = Math.max(dimensionsForDeltaTable[3], dimensionsOfCovTable[3]); + } + + return new NestedIntegerArray(dimensionsForDeltaTable); + } + + protected static List generateValuesFromKeys(final int[] keys, final Covariate[] covariates, final Map covariateNameMap) { final List values = new ArrayList(4); - values.add(covariates[RecalibrationTables.TableType.READ_GROUP_TABLE.ordinal()].formatKey((Integer)keys.get(0))); - final int covariateIndex = (Integer)keys.get(1); + values.add(covariates[RecalibrationTables.TableType.READ_GROUP_TABLE.ordinal()].formatKey(keys[0])); + + final int covariateIndex = keys[1]; + final int covariateKey = keys[2]; final Covariate covariate = covariateIndex == covariates.length ? covariates[RecalibrationTables.TableType.QUALITY_SCORE_TABLE.ordinal()] : covariates[covariateIndex]; - final int covariateKey = (Integer)keys.get(2); values.add(covariate.formatKey(covariateKey)); values.add(covariateNameMap.get(covariate)); - values.add(EventType.eventFrom((Integer)keys.get(3)).prettyPrint()); + values.add(EventType.eventFrom(keys[3]).prettyPrint()); return values; } @@ -501,20 +535,14 @@ public class RecalUtils { * @param deltaKey the key to the table * @param recalDatum the recal datum to combine with the accuracyDatum element in the table */ - private static void addToDeltaTable(final NestedHashMap deltaTable, final int[] deltaKey, final RecalDatum recalDatum) { - Object[] wrappedKey = wrapKeys(deltaKey); - final RecalDatum deltaDatum = (RecalDatum)deltaTable.get(wrappedKey); // check if we already have a RecalDatum for this key + private static void addToDeltaTable(final NestedIntegerArray deltaTable, final int[] deltaKey, final RecalDatum recalDatum) { + final RecalDatum deltaDatum = deltaTable.get(deltaKey); // check if we already have a RecalDatum for this key if (deltaDatum == null) - deltaTable.put(new RecalDatum(recalDatum), wrappedKey); // if we don't have a key yet, create a new one with the same values as the curent datum + // if we don't have a key yet, create a new one with the same values as the current datum + deltaTable.put(new RecalDatum(recalDatum), deltaKey); else - deltaDatum.combine(recalDatum); // if we do have a datum, combine it with this one. - } - - private static Object[] wrapKeys(final int[] keys) { - final Object[] wrappedKeys = new Object[keys.length]; - for (int i = 0; i < keys.length; i++) - wrappedKeys[i] = keys[i]; - return wrappedKeys; + // if we do have a datum, combine it with this one + deltaDatum.combine(recalDatum); } /** diff --git a/protected/java/test/org/broadinstitute/sting/gatk/walkers/bqsr/BQSRIntegrationTest.java b/protected/java/test/org/broadinstitute/sting/gatk/walkers/bqsr/BQSRIntegrationTest.java index 8a40b44e6..2149091af 100644 --- a/protected/java/test/org/broadinstitute/sting/gatk/walkers/bqsr/BQSRIntegrationTest.java +++ b/protected/java/test/org/broadinstitute/sting/gatk/walkers/bqsr/BQSRIntegrationTest.java @@ -151,7 +151,7 @@ public class BQSRIntegrationTest extends WalkerTest { " -sortAllCols" + " --plot_pdf_file /dev/null" + " --intermediate_csv_file %s", - Arrays.asList("dd6e0e1e3f53f8ae0c8f5de21ded6ee9")); + Arrays.asList("90ad19143024684e3c4410dc8fd2bd9d")); executeTest("testBQSR-CSVfile", spec); } diff --git a/public/java/src/org/broadinstitute/sting/utils/collections/NestedHashMap.java b/public/java/src/org/broadinstitute/sting/utils/collections/NestedHashMap.java deleted file mode 100644 index 9f330f226..000000000 --- a/public/java/src/org/broadinstitute/sting/utils/collections/NestedHashMap.java +++ /dev/null @@ -1,132 +0,0 @@ -/* -* Copyright (c) 2012 The Broad Institute -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -* THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -package org.broadinstitute.sting.utils.collections; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Created by IntelliJ IDEA. - * User: rpoplin - * Date: Dec 29, 2009 - */ - -public class NestedHashMap { - - public final Map data = new HashMap(); - - public Object get( final Object... keys ) { - Map map = this.data; - final int nestedMaps = keys.length - 1; - for( int iii = 0; iii < nestedMaps; iii++ ) { - map = (Map) map.get(keys[iii]); - if( map == null ) { return null; } - } - return map.get(keys[nestedMaps]); - } - - public synchronized void put( final Object value, final Object... keys ) { // WARNING! value comes before the keys! - this.put(value, false, keys ); - } - - public synchronized Object put( final Object value, boolean keepOldBindingIfPresent, final Object... keys ) { - Map map = this.data; - final int keysLength = keys.length; - for( int iii = 0; iii < keysLength; iii++ ) { - if( iii == keysLength - 1 ) { - if ( keepOldBindingIfPresent && map.containsKey(keys[iii]) ) { - // this code test is for parallel protection when you call put() multiple times in different threads - // to initialize the map. It returns the already bound key[iii] -> value - return map.get(keys[iii]); - } else { - // we are a new binding, put it in the map - map.put(keys[iii], value); - return value; - } - } else { - Map tmp = (Map) map.get(keys[iii]); - if( tmp == null ) { - tmp = new HashMap(); - map.put(keys[iii], tmp); - } - map = tmp; - } - } - - return value; // todo -- should never reach this point - } - - public List getAllValues() { - final List result = new ArrayList(); - fillAllValues(data, result); - return result; - } - - private void fillAllValues(final Map map, final List result) { - for ( Object value : map.values() ) { - if ( value == null ) - continue; - if ( value instanceof Map ) - fillAllValues((Map)value, result); - else - result.add(value); - } - } - - public static class Leaf { - public final List keys; - public final Object value; - - public Leaf(final List keys, final Object value) { - this.keys = keys; - this.value = value; - } - } - - public List getAllLeaves() { - final List result = new ArrayList(); - final List path = new ArrayList(); - fillAllLeaves(data, path, result); - return result; - } - - private void fillAllLeaves(final Map map, final List path, final List result) { - for ( final Object key : map.keySet() ) { - final Object value = map.get(key); - if ( value == null ) - continue; - final List newPath = new ArrayList(path); - newPath.add(key); - if ( value instanceof Map ) { - fillAllLeaves((Map) value, newPath, result); - } else { - result.add(new Leaf(newPath, value)); - } - } - } -}