<commit_before>//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package org.uma.jmetal.util.experiment.component;

import org.uma.jmetal.qualityindicator.QualityIndicator;
import org.uma.jmetal.qualityindicator.impl.GenericIndicator;
import org.uma.jmetal.solution.Solution;
import org.uma.jmetal.util.experiment.ExperimentComponent;
import org.uma.jmetal.util.experiment.ExperimentConfiguration;
import org.uma.jmetal.util.experiment.util.Pair;

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

/**
 * This class computes the Friedman test ranking and generates a Latex script that produces a table per
 * quality indicator containing the ranking
 *
 * The results are a set of Latex files that are written in the directory
 * {@link ExperimentConfiguration #getExperimentBaseDirectory()}/latex. Each file is called as
 * FriedmanTest[indicatorName].tex
 *
 * The implementation is based on the one included in Keel:
 * <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>,
 * <NAME>, <NAME>, <NAME>.
 * KEEL: A Software Tool to Assess Evolutionary Algorithms to Data Mining Problems. Soft Computing 13:3 (2009) 307-318
 * Doi: 10.1007/s00500-008-0323-y
 *
 * @author <NAME> <<EMAIL>>
 */

public class GenerateFriedmanTestTables<Result> implements ExperimentComponent {
  private static final String DEFAULT_LATEX_DIRECTORY = "latex";

  private final ExperimentConfiguration<?, Result> configuration;
  private List<GenericIndicator<? extends Solution<?>>> indicatorList ;

  private String latexDirectoryName ;

  @SuppressWarnings("unchecked")
  public GenerateFriedmanTestTables(ExperimentConfiguration experimentConfiguration) {
    this.configuration = experimentConfiguration ;
    this.indicatorList = experimentConfiguration.getIndicatorList() ;

    configuration.removeDuplicatedAlgorithms();
  }


  @Override
  public void run() throws IOException {
    latexDirectoryName = configuration.getExperimentBaseDirectory() + "/" + DEFAULT_LATEX_DIRECTORY;

    for (QualityIndicator indicator : configuration.getIndicatorList()) {
      computeDataStatistics(indicator);
    }
  }

  private void computeDataStatistics(QualityIndicator indicator) {
    Vector<String> algorithms = new Vector<String>();
    Vector<String> datasets = new Vector<String>();
    Vector data = new Vector();

    String outputFile =
        latexDirectoryName +"/FriedmanTest"+indicator.getName()+".tex";

    for (int algorithm = 0; algorithm < configuration.getAlgorithmList().size(); algorithm++) {
      String algorithmName = configuration.getAlgorithmList().get(algorithm).getTag();
      algorithms.add(new String(algorithmName));
      data.add(new Vector());
      String algorithmPath = configuration.getExperimentBaseDirectory() + "/data/"
          + algorithmName + "/";

      for (int problem = 0; problem < configuration.getProblemList().size(); problem++) {
        if (algorithm == 0) {
          datasets.add(configuration.getProblemList().get(problem).getName());
        }

        String path = algorithmPath + configuration.getProblemList().get(problem).getName() +
            "/" + indicator.getName();

        //Leemos el fichero
        String string = "";

        try {
          FileInputStream fis = new FileInputStream(path);

          byte[] leido = new byte[4096];
          int bytesLeidos = 0;

          while (bytesLeidos != -1) {
            bytesLeidos = fis.read(leido);

            if (bytesLeidos != -1) {
              string += new String(leido, 0, bytesLeidos);
            }
          }

          fis.close();
        } catch (IOException e) {
          e.printStackTrace();
          System.exit(-1);
        }

        StringTokenizer lines = new StringTokenizer(string, "\n\r");

        double valor = 0.0;
        int n = 0;

        while (lines.hasMoreTokens()) {
          valor = valor + Double.parseDouble(lines.nextToken());
          n++;
        }
        if (n != 0) {
          ((Vector) data.elementAt(algorithm)).add(new Double(valor / n));
        } else {
          ((Vector) data.elementAt(algorithm)).add(new Double(valor));
        }
      }
    }

      /*Compute the average performance per algorithm for each data set*/
    double[][] mean = new double[datasets.size()][algorithms.size()];

    for (int j = 0; j < algorithms.size(); j++) {
      for (int i = 0; i < datasets.size(); i++) {
        mean[i][j] = ((Double)((Vector)data.elementAt(j)).elementAt(i)).doubleValue();
      }
    }

          /*We use the pareja structure to compute and order rankings*/
    Pair[][] order = new Pair[datasets.size()][algorithms.size()];

    for (int i=0; i<datasets.size(); i++) {
      for (int j=0; j<algorithms.size(); j++){
        order[i][j] = new Pair (j,mean[i][j]);
      }
      Arrays.sort(order[i]);
    }

          /*building of the rankings table per algorithms and data sets*/
    Pair[][] rank = new Pair[datasets.size()][algorithms.size()];
    int position = 0;
    for (int i=0; i<datasets.size(); i++) {
      for (int j=0; j<algorithms.size(); j++){
        boolean found  = false;
        for (int k=0; k<algorithms.size() && !found; k++) {
          if (order[i][k].index == j) {
            found = true;
            position = k+1;
          }
        }
        rank[i][j] = new Pair(position,order[i][position-1].value);
      }
    }

    /*In the case of having the same performance, the rankings are equal*/
    for (int i=0; i<datasets.size(); i++) {
      boolean[] visto = new boolean[algorithms.size()];
      Vector porVisitar= new Vector();

      Arrays.fill(visto,false);
      for (int j=0; j<algorithms.size(); j++) {
        porVisitar.removeAllElements();
        double sum = rank[i][j].index;
        visto[j] = true;
        int ig = 1;
        for (int k=j+1;k<algorithms.size();k++) {
          if (rank[i][j].value == rank[i][k].value && !visto[k]) {
            sum += rank[i][k].index;
            ig++;
            porVisitar.add(new Integer(k));
            visto[k] = true;
          }
        }
        sum /= (double)ig;
        rank[i][j].index = sum;
        for (int k=0; k<porVisitar.size(); k++) {
          rank[i][((Integer)porVisitar.elementAt(k)).intValue()].index = sum;
        }
      }
    }

    /*compute the average ranking for each algorithm*/
    double []averageRanking = new double[algorithms.size()];
    for (int i=0; i<algorithms.size(); i++){
      averageRanking[i] = 0;
      for (int j=0; j<datasets.size(); j++) {
        averageRanking[i] += rank[j][i].index / ((double)datasets.size());
      }
    }

    String fileContents = writeLatexHeader();
    fileContents = printTableHeader(fileContents) ;
    fileContents = printTableLines(fileContents, algorithms, averageRanking) ;
    fileContents = printTableTail(fileContents) ;
    fileContents = printDocumentFooter(fileContents, datasets, averageRanking) ;
    writeLatexFile(outputFile, fileContents);
  }

  /**
   * Write the file contents in the output file
   * @param outputFile
   * @param fileContents
   */
  private void writeLatexFile(String outputFile, String fileContents) {
    try {
      File latexOutput;
      latexOutput = new File(latexDirectoryName);
      if(!latexOutput.exists()){
        latexOutput.mkdirs();
      }
      FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
      DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);

      dataOutputStream.writeBytes(fileContents);

      dataOutputStream.close();
      fileOutputStream.close();
    }
    catch (IOException e) {
      e.printStackTrace();
      System.exit(-1);
    }
  }

  private String writeLatexHeader() {
    String latexHeader = ("\\documentclass{article}\n" +
        "\\usepackage{graphicx}\n" +
        "\\title{Results}\n" +
        "\\author{}\n" +
        "\\date{\\today}\n" +
        "\\begin{document}\n" +
        "\\oddsidemargin 0in \\topmargin 0in" +
        "\\maketitle\n" +
        "\\\n" +
        "\\section{Tables}");

    return latexHeader ;
  }

  private String printTableLines(String fileContents, Vector<String> algorithms, double[] averageRanking) {
    String output = fileContents ;
    for (int i=0; i<algorithms.size();i++) {
      output += "\n" + algorithms.elementAt(i)+"&"+averageRanking[i]+"\\\\";
    }

    return output ;
  }

  private String printTableTail(String fileContents) {
    return fileContents + "\n" +
        "\\end{tabular}\n" +
        "\\end{table}";
  }

  private String printTableHeader(String fileContents) {
    return fileContents + "\n"+("\\begin{table}[!htp]\n" +
        "\\centering\n" +
        "\\caption{Average ranking of the algorithms}\n"+
        "\\begin{tabular}{c|c}\n" +
        "Algorithm&Ranking\\\\\n\\hline");
  }

  private String printDocumentFooter(String fileContents, Vector<String> datasets, double[] averageRanking) {
    double numberOfAlgorithms = configuration.getAlgorithmList().size() ;
    double termino1 = (12*(double)datasets.size())/(numberOfAlgorithms*(numberOfAlgorithms+1));
    double termino2 = numberOfAlgorithms*(numberOfAlgorithms+1)*(numberOfAlgorithms+1)/(4.0);
    double sumatoria = 0;
    for (int i=0; i<numberOfAlgorithms;i++) {
      sumatoria += averageRanking[i] * averageRanking[i];
    }
    double friedman = (sumatoria - termino2) * termino1;

    String output = fileContents + "\n" + "\n\nFriedman statistic considering reduction performance (distributed according to " +<commit_msg>Still refactoring<commit_after>//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package org.uma.jmetal.util.experiment.component;

import org.uma.jmetal.qualityindicator.QualityIndicator;
import org.uma.jmetal.qualityindicator.impl.GenericIndicator;
import org.uma.jmetal.solution.Solution;
import org.uma.jmetal.util.experiment.ExperimentComponent;
import org.uma.jmetal.util.experiment.ExperimentConfiguration;
import org.uma.jmetal.util.experiment.util.Pair;

import java.io.*;
import java.util.*;

/**
 * This class computes the Friedman test ranking and generates a Latex script that produces a table per
 * quality indicator containing the ranking
 *
 * The results are a set of Latex files that are written in the directory
 * {@link ExperimentConfiguration #getExperimentBaseDirectory()}/latex. Each file is called as
 * FriedmanTest[indicatorName].tex
 *
 * The implementation is based on the one included in Keel:
 * <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>,
 * <NAME>, <NAME>, <NAME>.
 * KEEL: A Software Tool to Assess Evolutionary Algorithms to Data Mining Problems. Soft Computing 13:3 (2009) 307-318
 * Doi: 10.1007/s00500-008-0323-y
 *
 * @author <NAME> <<EMAIL>>
 */

public class GenerateFriedmanTestTables<Result> implements ExperimentComponent {
  private static final String DEFAULT_LATEX_DIRECTORY = "latex";

  private final ExperimentConfiguration<?, Result> configuration;
  private List<GenericIndicator<? extends Solution<?>>> indicatorList ;

  private String latexDirectoryName ;

  @SuppressWarnings("unchecked")
  public GenerateFriedmanTestTables(ExperimentConfiguration experimentConfiguration) {
    this.configuration = experimentConfiguration ;
    this.indicatorList = experimentConfiguration.getIndicatorList() ;

    configuration.removeDuplicatedAlgorithms();
  }


  @Override
  public void run() throws IOException {
    latexDirectoryName = configuration.getExperimentBaseDirectory() + "/" + DEFAULT_LATEX_DIRECTORY;

    for (QualityIndicator indicator : configuration.getIndicatorList()) {
      computeDataStatistics(indicator);
    }
  }

  private void computeDataStatistics(QualityIndicator indicator) {
    Vector<String> datasets = new Vector<String>();
    Vector<Vector<Double>> data = new Vector<>();

    String outputFile =
        latexDirectoryName +"/FriedmanTest"+indicator.getName()+".tex";

    int numberOfAlgorithms = configuration.getAlgorithmList().size() ;

    for (int algorithm = 0; algorithm < configuration.getAlgorithmList().size(); algorithm++) {
      String algorithmName = configuration.getAlgorithmList().get(algorithm).getTag();

      data.add(new Vector<Double>());
      String algorithmPath = configuration.getExperimentBaseDirectory() + "/data/"
          + algorithmName + "/";

      for (int problem = 0; problem < configuration.getProblemList().size(); problem++) {
        if (algorithm == 0) {
          datasets.add(configuration.getProblemList().get(problem).getName());
        }

        String path = algorithmPath + configuration.getProblemList().get(problem).getName() +
            "/" + indicator.getName();

        readDataFromFile(path, data, algorithm) ;
      }
    }

      /*Compute the average performance per algorithm for each data set*/
    double[][] mean = new double[datasets.size()][numberOfAlgorithms];

    for (int j = 0; j < numberOfAlgorithms; j++) {
      for (int i = 0; i < datasets.size(); i++) {
        mean[i][j] = ((Double)((Vector)data.elementAt(j)).elementAt(i)).doubleValue();
      }
    }

          /*We use the pareja structure to compute and order rankings*/
    Pair[][] order = new Pair[datasets.size()][numberOfAlgorithms];

    for (int i=0; i<datasets.size(); i++) {
      for (int j=0; j<numberOfAlgorithms; j++){
        order[i][j] = new Pair(j,mean[i][j]);
      }
      Arrays.sort(order[i]);
    }

          /*building of the rankings table per algorithms and data sets*/
    Pair[][] rank = new Pair[datasets.size()][numberOfAlgorithms];
    int position = 0;
    for (int i=0; i<datasets.size(); i++) {
      for (int j=0; j<numberOfAlgorithms; j++){
        boolean found  = false;
        for (int k=0; k<numberOfAlgorithms && !found; k++) {
          if (order[i][k].index == j) {
            found = true;
            position = k+1;
          }
        }
        rank[i][j] = new Pair(position,order[i][position-1].value);
      }
    }

    /*In the case of having the same performance, the rankings are equal*/
    for (int i=0; i<datasets.size(); i++) {
      boolean[] visto = new boolean[numberOfAlgorithms];
      Vector porVisitar= new Vector();

      Arrays.fill(visto,false);
      for (int j=0; j<numberOfAlgorithms; j++) {
        porVisitar.removeAllElements();
        double sum = rank[i][j].index;
        visto[j] = true;
        int ig = 1;
        for (int k=j+1;k<numberOfAlgorithms;k++) {
          if (rank[i][j].value == rank[i][k].value && !visto[k]) {
            sum += rank[i][k].index;
            ig++;
            porVisitar.add(new Integer(k));
            visto[k] = true;
          }
        }
        sum /= (double)ig;
        rank[i][j].index = sum;
        for (int k=0; k<porVisitar.size(); k++) {
          rank[i][((Integer)porVisitar.elementAt(k)).intValue()].index = sum;
        }
      }
    }

    /*compute the average ranking for each algorithm*/
    double []averageRanking = new double[numberOfAlgorithms];
    for (int i=0; i<numberOfAlgorithms; i++){
      averageRanking[i] = 0;
      for (int j=0; j<datasets.size(); j++) {
        averageRanking[i] += rank[j][i].index / ((double)datasets.size());
      }
    }

    String fileContents = writeLatexHeader();
    fileContents = printTableHeader(fileContents) ;
    fileContents = printTableLines(fileContents, averageRanking) ;
    fileContents = printTableTail(fileContents) ;
    fileContents = printDocumentFooter(fileContents, datasets, averageRanking) ;
    writeLatexFile(outputFile, fileContents);
  }

  private void readDataFromFile(String path, Vector<Vector<Double>> data, int algorithmIndex) {
    String string = "";

    try {
      FileInputStream fis = new FileInputStream(path);

      byte[] leido = new byte[4096];
      int bytesLeidos = 0;

      while (bytesLeidos != -1) {
        bytesLeidos = fis.read(leido);

        if (bytesLeidos != -1) {
          string += new String(leido, 0, bytesLeidos);
        }
      }

      fis.close();
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(-1);
    }

    StringTokenizer lines = new StringTokenizer(string, "\n\r");

    double valor = 0.0;
    int n = 0;

    while (lines.hasMoreTokens()) {
      valor = valor + Double.parseDouble(lines.nextToken());
      n++;
    }
    if (n != 0) {
      (data.elementAt(algorithmIndex)).add(new Double(valor / n));
    } else {
      (data.elementAt(algorithmIndex)).add(new Double(valor));
    }
  }

  /**
   * Write the file contents in the output file
   * @param outputFile
   * @param fileContents
   */
  private void writeLatexFile(String outputFile, String fileContents) {
    try {
      File latexOutput;
      latexOutput = new File(latexDirectoryName);
      if(!latexOutput.exists()){
        latexOutput.mkdirs();
      }
      FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
      DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);

      dataOutputStream.writeBytes(fileContents);

      dataOutputStream.close();
      fileOutputStream.close();
    }
    catch (IOException e) {
      e.printStackTrace();
      System.exit(-1);
    }
  }

  private String writeLatexHeader() {
    String latexHeader = ("\\documentclass{article}\n" +
        "\\usepackage{graphicx}\n" +
        "\\title{Results}\n" +
        "\\author{}\n" +
        "\\date{\\today}\n" +
        "\\begin{document}\n" +
        "\\oddsidemargin 0in \\topmargin 0in" +
        "\\maketitle\n" +
        "\\\n" +
        "\\section{Tables}");

    return latexHeader ;
  }

  private String printTableLines(String fileContents, double[] averageRanking) {
    String output = fileContents ;
    for (int i=0; i<configuration.getAlgorithmList().size();i++) {
      output += "\n" + configuration.getAlgorithmList().get(i).getTag()+"&"+averageRanking[i]+"\\\\";
    }

    return output ;
  }

  private String printTableTail(String fileContents) {
    return fileContents + "\n" +
        "\\end{tabular}\n" +
        "\\end{table}";
  }

  private String printTableHeader(String fileContents) {
    return fileContents + "\n"+("\\begin{table}[!htp]\n" +
        "\\centering\n" +
        "\\caption{Average ranking of the algorithms}\n"+
        "\\begin{tabular}{c|c}\n" +
        "Algorithm&Ranking\\\\\n\\hline");
  }

  private String printDocumentFooter(String fileContents, Vector<String> datasets, double[] averageRanking) {
    double numberOfAlgorithms = configuration.getAlgorithmList().size() ;
    double term1 = (12*(double)datasets.size())/(numberOfAlgorithms*(numberOfAlgorithms+1));
    double term2 = numberOfAlgorithms*(numberOfAlgorithms+1)*(numberOfAlgorithms+1)/(4.0);
    double sum = 0;
    for (int i=0; i<numberOfAlgorithms;i++) {
      sum += averageRanking[i] * averageRanking[i];
    }
    double friedman = (sum - term2) * term1;

    String output = fileContents + "\n" + "\n\nFriedman statistic considering reduction performance (distributed according to " +
{'fraction_non_alphanumeric': 0.1363030273099906, 'fraction_numerical': 0.008197935700528422, 'mean_word_length': 3.0274463007159906, 'pattern_counts': {'":': 0, '<': 94, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3442029', 'n_tokens_mistral': 6093, 'n_tokens_neox': 5816, 'n_words': 1484}