RegionalSensitivityAnalyzer.java [src/java/m/sensitivity/model/methods] Revision: default  Date:
package m.sensitivity.model.methods;

import m.sensitivity.model.util.MathUtil;
import m.sensitivity.model.util.SortUtil;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class RegionalSensitivityAnalyzer implements SensitivityAnalyzer {

    @Override
    public String getName() {
        return "rsa";
    }

    @Override
    public Map<String, Double> compute(Map<String, List<Double>> parameters, List<Double> metric, boolean isPositiveBest) {
        int numberOfParameters = parameters.size();
        if (numberOfParameters < 1) {
            return new HashMap<>();
        }
        int sampleSize = parameters.values().iterator().next().size();

        List<Double> likelihood = isPositiveBest ? likelihoodPositiveBest(metric) : likelihoodZeroBest(metric);
        List<Integer> sortedLikelihoodIndices = SortUtil.indicesOfSortedOrder(likelihood);

        List<Integer> mostLikely = new ArrayList<>();
        List<Integer> leastLikely = new ArrayList<>();
        int splitIndex = (sampleSize & 0x1) == 0x0
                ? sampleSize / 2
                : (sampleSize + 1) / 2;
        for (int i = 0; i < splitIndex; ++i) {
            leastLikely.add(sortedLikelihoodIndices.get(i));
        }
        for (int i = splitIndex; i < sampleSize; ++i) {
            mostLikely.add(sortedLikelihoodIndices.get(i));
        }

        Map<String, Double> sensitivity = new LinkedHashMap<>();
        for (Map.Entry<String, List<Double>> parameter : parameters.entrySet()) {
            final String currentName = parameter.getKey();
            final List<Double> currentValues = parameter.getValue();

            Comparator<Integer> comparator = Comparator.comparingDouble(currentValues::get);
            mostLikely.sort(comparator);
            leastLikely.sort(comparator);

            sensitivity.put(currentName, 0.0);
            for (int mostLikelyIndex = 0, leastLikelyIndex = 0; mostLikelyIndex < mostLikely.size(); ++mostLikelyIndex) {
                double mostLikelyValue = currentValues.get(mostLikely.get(mostLikelyIndex));

                while (leastLikelyIndex < leastLikely.size()) {
                    double leastLikelyValue = currentValues.get(leastLikely.get(leastLikelyIndex));
                    if (leastLikelyValue >= mostLikelyValue) {
                        break;
                    }
                    ++leastLikelyIndex;
                }

                double mostLikelyDistribution = ((double) (mostLikelyIndex + 1)) / mostLikely.size();
                double leastLikelyDistribution = ((double) (leastLikelyIndex + 1)) / leastLikely.size();
                double s = Math.abs(mostLikelyDistribution - leastLikelyDistribution);
                if (s > sensitivity.get(currentName)) {
                    sensitivity.put(currentName, s);
                }
            }
        }

        MathUtil.normalize(sensitivity);
        return sensitivity;
    }

    private static List<Double> likelihoodPositiveBest(List<Double> values) {
        double min = MathUtil.findMin(values);

        List<Double> likelihood = new ArrayList<>();
        for (double value : values) {
            likelihood.add(value - min);
        }

        MathUtil.normalize(likelihood);
        return likelihood;
    }

    private static List<Double> likelihoodZeroBest(List<Double> values) {
        List<Double> positiveBest = new ArrayList<>();
        for (double value : values) {
            if (value == 0.0) {
                positiveBest.add(Double.MAX_VALUE);
            } else {
                positiveBest.add(1.0 / Math.abs(value));
            }
        }

        return likelihoodPositiveBest(positiveBest);
    }
}