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

import com.ezylang.evalex.Expression;
import com.ezylang.evalex.data.EvaluationValue;
import java.io.BufferedReader;
import java.io.File;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import m.sensitivity.model.methods.SensitivityAnalyzer;

/**
 *
 * @author nathan
 */
public class Executor {

    private final Path trace;

    private final List<String> parameters;
    private final List<String> positiveBestMetrics;
    private final List<String> zeroBestMetrics;
    private final List<Map<String, Object>> customMetrics;

    private final Map<String, List<Double>> parameterMap = new LinkedHashMap<>();
    private final Map<String, List<Double>> metricMap = new HashMap<>();

    private boolean init = false;

    public Executor(File trace, String[] parameters,
            String[] positiveBestMetrics, String[] zeroBestMetrics,
            List<Map<String, Object>> customMetrics) {
        this.trace = trace.toPath();
        this.parameters = new ArrayList<>(Arrays.asList(parameters));
        this.positiveBestMetrics = new ArrayList<>(Arrays.asList(positiveBestMetrics));
        this.zeroBestMetrics = new ArrayList<>(Arrays.asList(zeroBestMetrics));
        this.customMetrics = customMetrics;

        for (Map<String, Object> map : this.customMetrics) {
            String name = String.valueOf(map.get("name"));
            boolean positiveBest = (Boolean) map.get("positiveBest");

            if (positiveBest) {
                this.positiveBestMetrics.add(name);
            } else {
                this.zeroBestMetrics.add(name);
            }
        }
    }

    public void execute(SensitivityAnalyzer sa, Path outputDirectory) {
        if (!init) {
            readTrace();
            init = true;
        }

        for (String metric : positiveBestMetrics) {
            execute(sa, metric, true, outputDirectory);
        }
        for (String metric : zeroBestMetrics) {
            execute(sa, metric, false, outputDirectory);
        }
    }

    private void readTrace() {
        try (BufferedReader reader = Files.newBufferedReader(trace)) {
            String header = reader.readLine();
            String[] split = header.split(",");
            Map<String, Integer> indexMap = new HashMap<>();
            for (int i = 0; i < split.length; ++i) {
                indexMap.put(split[i], i);
            }

            Set<String> params = new HashSet<>();
            Set<String> metrics = new HashSet<>();
            for (String p : parameters) {
                if (indexMap.containsKey(p)) {
                    params.add(p);
                    parameterMap.put(p, new ArrayList<>());
                }
            }
            for (String m : positiveBestMetrics) {
                if (indexMap.containsKey(m)) {
                    metrics.add(m);
                    metricMap.put(m, new ArrayList<>());
                }
            }
            for (String m : zeroBestMetrics) {
                if (indexMap.containsKey(m)) {
                    metrics.add(m);
                    metricMap.put(m, new ArrayList<>());
                }
            }

            String line;
            while ((line = reader.readLine()) != null) {
                split = line.split(",");
                for (String p : params) {
                    int i = indexMap.get(p);
                    parameterMap.get(p).add(Double.valueOf(split[i]));
                }
                for (String m : metrics) {
                    if (indexMap.containsKey(m)) {
                        int i = indexMap.get(m);
                        metricMap.get(m).add(Double.valueOf(split[i]));
                    }
                }

                if (!customMetrics.isEmpty()) {
                    Map<String, Double> values = new HashMap<>();
                    for (Map.Entry<String, Integer> entry : indexMap.entrySet()) {
                        values.put(entry.getKey(), Double.valueOf(split[entry.getValue()]));
                    }

                    for (Map<String, Object> customMetric : customMetrics) {
                        String name = String.valueOf(customMetric.get("name"));
                        String value = String.valueOf(customMetric.get("value"));

                        Expression exp = new Expression(value);
                        EvaluationValue result = exp.withValues(values).evaluate();
                        if (metricMap.containsKey(name)) {
                            metricMap.get(name).add(result.getNumberValue().doubleValue());
                        } else {
                            List<Double> list = new ArrayList<>();
                            list.add(result.getNumberValue().doubleValue());
                            metricMap.put(name, list);
                        }
                    }
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException("Error reading values: " + trace, ex);
        }
    }

    private void execute(SensitivityAnalyzer sa, String metric, boolean isPositiveBest, Path outputDirectory) {
        if (metricMap.containsKey(metric)) {
            Map<String, Double> sensitivityMap = sa.compute(parameterMap, metricMap.get(metric), isPositiveBest);
            sensitivityMap = sortMapByValueReversed(sensitivityMap);
            Path outputFilePath = outputDirectory.resolve("output_" + sa.getName() + "_" + metric + ".csv");
            writeOutput(outputFilePath, sensitivityMap);
        }
    }

    private static Map<String, Double> sortMapByValueReversed(Map<String, Double> map) {
        List<Map.Entry<String, Double>> list = new ArrayList<>(map.entrySet());
        list.sort((o1, o2) -> {
            // reverse order so the highest value is first
            return Double.compare(o2.getValue(), o1.getValue());
        });

        Map<String, Double> result = new LinkedHashMap<>();
        for (Map.Entry<String, Double> entry : list) {
            result.put(entry.getKey(), entry.getValue());
        }

        return result;
    }

    private static void writeOutput(Path outputFilePath, Map<String, Double> sensitivityMap) {
        try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(outputFilePath))) {
            writer.println("parameter,sensitivity");
            for (Map.Entry<String, Double> entry : sensitivityMap.entrySet()) {
                writer.println(entry.getKey() + "," + entry.getValue());
            }
        } catch (Exception ex) {
            throw new RuntimeException("Failed to write output: " + outputFilePath, ex);
        }
    }
}