package org.intermine.web.logic.widget;

/*
 * Copyright (C) 2002-2007 FlyMine
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  See the LICENSE file for more
 * information or http://www.gnu.org/copyleft/lesser.html.
 *
 */

import java.util.HashMap;
import java.util.Iterator;

import org.intermine.web.logic.SortableMap;

import java.math.BigDecimal;

/**
 * @author Julie Sullivan
 */
public class BenjaminiHochberg implements ErrorCorrection
{
    private HashMap<String, Double> originalMap = new HashMap<String, Double>();
    private HashMap<String, BigDecimal> adjustedMap = new HashMap<String, BigDecimal>();
    private double numberOfTests;
    private static final int RESULT_SCALE = 100;

    /**
     * @param numberOfTests number of tests we've run, excluding terms that only annotate one item
     * as these cannot possibly be over-represented
     * @param originalMap HashMap of go terms and their p-value
     * @param alpha the error rate user is willing to accept
     */
    public BenjaminiHochberg(HashMap<String, Double> originalMap, int numberOfTests) {
        this.numberOfTests = numberOfTests;
        SortableMap sortedMap = new SortableMap(originalMap);
        // sort descending
        sortedMap.sortValues(false, false);
        this.originalMap = new HashMap<String, Double>(sortedMap);
    }

    /**
     * Calculates the Benjamini and Hochberg correction of
     * the false discovery rate
     * @param max maximum value we are interested in.  
     */
    public void calculate(Double max) {

        adjustedMap = new HashMap<String, BigDecimal>();
        BigDecimal adjustedP;
        int i = 1;

        for (Iterator iter = originalMap.keySet().iterator(); iter.hasNext(); i++) {

            String label = (String) iter.next();
            BigDecimal k = new BigDecimal("" + i);
            BigDecimal m = new BigDecimal("" + numberOfTests);
            
            BigDecimal p = new BigDecimal("" + originalMap.get(label));
            adjustedP = k.divide(m, RESULT_SCALE, BigDecimal.ROUND_HALF_UP);
            adjustedP = p.multiply(adjustedP);

            if (adjustedP.doubleValue() < max.doubleValue()) {
                adjustedMap.put(label, adjustedP);
            }
        }
    }

    /**
     * @return adjusted map
     */
    public HashMap<String, BigDecimal> getAdjustedMap() {
        return adjustedMap;
    }

}



@@ -465,16 +465,706 @@
 l;%0A%0A/**%0A
+ * This correction is the less stringent than the Bonferroni, and therefore tolerates more%0A * false positives. There will be also less false negative genes. Here is how it works:%0A *  1) The p-values of each gene are ranked from the smallest to the largest.%0A *  2) The largest p-value remains as it is.%0A *  3) The second largest p-value is multiplied by the total number of genes in gene%0A *      list divided by its rank. If less than 0.05, it is significant.%0A *      Corrected p-value = p-value*(n/n-1) %3C 0.05, if so, gene is significant.%0A *  4) The third p-value is multiplied as in step 3:%0A *      Corrected p-value = p-value*(n/n-2) %3C 0.05, if so, gene is significant.%0A * And so on.%0A * %0A
  * @auth
@@ -1726,69 +1726,8 @@
 lue%0A
-     * @param alpha the error rate user is willing to accept%0A
     
@@ -1939,18 +1939,17 @@
 // sort 
-de
+a
 scending
@@ -2218,17 +2218,49 @@
 ested in
-.
+ - used for display purposes only
   %0A     
@@ -2568,17 +2568,21 @@
 Decimal 
-k
+index
  = new B
@@ -2662,17 +2662,16 @@
 fTests);
-%0A
         
@@ -2746,16 +2746,86 @@
 label));
+ // unadjusted p-value%0A            %0A            // p-value * (n/index)
 %0A       
@@ -2845,17 +2845,17 @@
 P = 
-k
+m
 .divide(
 m, R
@@ -2850,17 +2850,21 @@
 .divide(
-m
+index
 , RESULT

fix for enrichment widget's multiple test correction