// Path: src/main/java/org/latna/msw/euclidian/EuclidianFactory.java
// public class EuclidianFactory implements MetricElementFactory, Supplier<MetricElement>  {
//     
//     private int dimension; 
//     private int n; //number of elements
//     private List <MetricElement> allElements;
//     private static Random random =  new Random();
// 
//     public List<MetricElement> getElements() {
//         allElements = new ArrayList(n);
//         
//         for (int i=0; i < n; i++) {
//             double x[] = new double[dimension];
//             for (int j=0; j < dimension; j++) {
//                 x[j] = random.nextDouble();
//             }
//             
//             allElements.add(new Euclidean(x));
//         }
//         return allElements;
//     }
// 
//     public void setParameterString(String param) {
//         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
//     }
//     
//     /*
// 
//     * Create factory and generate list with n uniformaly distributed elements
//      * @param dimension
//      * @param n - number of elements 
//      * @param seed - random seed
//      */    
//     public EuclidianFactory(int dimension, int n) {
//         this.dimension = dimension;
//         this.n = n;
//     }
//     
//     public static MetricElement getRandomElement(int dimension) {
//         double x[] = new double[dimension];
//             for (int j=0; j < dimension; j++) {
//                 x[j] = random.nextDouble();
//             }
//         return new Euclidean(x);
//     }
//     
//     public EuclidianFactory(int dimension, int n, double standardDeviation) {
//         this.dimension = dimension;
//         this.n = n;
//         
//         RandomEngine engine = new DRand();
//         Normal normal = new Normal(0, standardDeviation, engine);
//         
//         allElements = new ArrayList(n);
//         
//         for (int i=0; i < n; i++) {
//             double x[] = new double[dimension];
//             for (int j=0; j < dimension; j++) {
//                 x[j] = normal.nextDouble();
//             }
//             
//             allElements.add(new Euclidean(x)); 
//         }
//     }
//     
//     
//     public int getDimension() {
//         return dimension;
//     }
// 
//     @Override
//     public MetricElement get() {
//         double x[] = new double[dimension];
//         for (int j=0; j < dimension; j++) {
//             x[j] = random.nextDouble();
//         }
//         return new Euclidean(x);
//     }
// }


import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import org.latna.msw.euclidian.EuclidianFactory;
        
        fw.append(msg);
        fw.flush();
    }
    
    public static Vector <Integer> getShortestPathDistribution(List<MetricElement> allElements) {

        Vector <Integer> spDistribution = new Vector <Integer> ();
        //allElements.parallelStream().forEach(s->{
        allElements.stream().forEach(s->{
            Map <MetricElement, Integer> sp  = getShortestPathValueMap(allElements, s);
            //synchronized (spDistribution) {
                for (Integer v: sp.values()) {
                    spDistribution.add(v, spDistribution.get(v) + 1);
              //  }
            }
        });
        
        return spDistribution;
    };
 /*
    public static Object getRandomElement(List allElements) {
        if (allElements.size() == 0) return null;
        return allElements.get(random.nextInt(allElements.size()));
    }
   */
    
    /**
     * returns <query, List of search results> 
    */
// Path: src/main/java/org/latna/msw/euclidian/EuclidianFactory.java
// public class EuclidianFactory implements MetricElementFactory, Supplier<MetricElement>  {
//     
//     private int dimension; 
//     private int n; //number of elements
//     private List <MetricElement> allElements;
//     private static Random random =  new Random();
// 
//     public List<MetricElement> getElements() {
//         allElements = new ArrayList(n);
//         
//         for (int i=0; i < n; i++) {
//             double x[] = new double[dimension];
//             for (int j=0; j < dimension; j++) {
//                 x[j] = random.nextDouble();
//             }
//             
//             allElements.add(new Euclidean(x));
//         }
//         return allElements;
//     }
// 
//     public void setParameterString(String param) {
//         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
//     }
//     
//     /*
// 
//     * Create factory and generate list with n uniformaly distributed elements
//      * @param dimension
//      * @param n - number of elements 
//      * @param seed - random seed
//      */    
//     public EuclidianFactory(int dimension, int n) {
//         this.dimension = dimension;
//         this.n = n;
//     }
//     
//     public static MetricElement getRandomElement(int dimension) {
//         double x[] = new double[dimension];
//             for (int j=0; j < dimension; j++) {
//                 x[j] = random.nextDouble();
//             }
//         return new Euclidean(x);
//     }
//     
//     public EuclidianFactory(int dimension, int n, double standardDeviation) {
//         this.dimension = dimension;
//         this.n = n;
//         
//         RandomEngine engine = new DRand();
//         Normal normal = new Normal(0, standardDeviation, engine);
//         
//         allElements = new ArrayList(n);
//         
//         for (int i=0; i < n; i++) {
//             double x[] = new double[dimension];
//             for (int j=0; j < dimension; j++) {
//                 x[j] = normal.nextDouble();
//             }
//             
//             allElements.add(new Euclidean(x)); 
//         }
//     }
//     
//     
//     public int getDimension() {
//         return dimension;
//     }
// 
//     @Override
//     public MetricElement get() {
//         double x[] = new double[dimension];
//         for (int j=0; j < dimension; j++) {
//             x[j] = random.nextDouble();
//         }
//         return new Euclidean(x);
//     }
// }


// Path: src/main/java/org/latna/msw/TestLib.java
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import org.latna.msw.euclidian.EuclidianFactory;

        
        fw.append(msg);
        fw.flush();
    }
    
    public static Vector <Integer> getShortestPathDistribution(List<MetricElement> allElements) {

        Vector <Integer> spDistribution = new Vector <Integer> ();
        //allElements.parallelStream().forEach(s->{
        allElements.stream().forEach(s->{
            Map <MetricElement, Integer> sp  = getShortestPathValueMap(allElements, s);
            //synchronized (spDistribution) {
                for (Integer v: sp.values()) {
                    spDistribution.add(v, spDistribution.get(v) + 1);
              //  }
            }
        });
        
        return spDistribution;
    };
 /*
    public static Object getRandomElement(List allElements) {
        if (allElements.size() == 0) return null;
        return allElements.get(random.nextInt(allElements.size()));
    }
   */
    
    /**
     * returns <query, List of search results> 
    */
    public static Map <MetricElement, List<EvaluationResult>> evaluateSearchAlgorithm(List<MetricElement> allElements, EuclidianFactory testQueryFactory, int numberOfQueries, int numberOfTries) {