// returns the distance between this cluster and another one
    // we use a complete link approach for hierarchical clustering,
    // so this is the maximum distance between two members of each
    // cluster
    public float Distance(CandidateCluster other, bool useBestPosition)
    {
        // get leaf nodes of this cluster
        List <CLCandidate> leaves = GetCandidatesInCluster();

        // get leaf nodes of other cluster
        List <CLCandidate> otherLeaves = other.GetCandidatesInCluster();

        // compute max distance
        float distance = 0.0f;

        foreach (CLCandidate c1 in leaves)
        {
            foreach (CLCandidate c2 in otherLeaves)
            {
                float d = c1.Distance(c2, useBestPosition);
                if (d > distance)
                {
                    distance = d;
                }
            }
        }

        return(distance);
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="CandidatesClustering"/> class and performs clusterng
    /// </summary>
    /// <param name="solver">Solver, whose found solutions we want to cluster</param>
    /// <param name="minSat">Minimum sat. We will exclude solutions that do not reach this sat.</param>
    /// <param name="maxDistance">Max distance.</param>
    /// <param name="maxClusters">Max clusters. Maximum number of clusters to build</param>
    public HierarchicalClustering(CLSolver solver, float minSat, bool useBestPosition)
    {
        List <CandidateCluster> clusters = new List <CandidateCluster> ();

        // select only candidates with sat >= minSat and assign each candidate to a cluster
        for (int i = 0; i < solver.numberOfCandidates; i++)
        {
            if (solver.candidates[i].bestEvaluation >= minSat)
            {
                clusters.Add(new CandidateCluster(solver.candidates[i]));
            }
        }

        Debug.Log("found " + clusters.Count + " candidates with min sat");

        // now, loop until |clusters| = 1
        while (clusters.Count > 1)
        {
            // compute distances matrix
            float[,] distances = ComputeDistanceMatrix(clusters, useBestPosition);

            // find closest clusters
            int   cluster1    = 0;
            int   cluster2    = 0;
            float minDistance = Mathf.Infinity;
            for (int i = 0; i < clusters.Count; i++)
            {
                for (int j = 0; j < clusters.Count; j++)
                {
                    if (i > j)                        // we need to compute distance
                    {
                        if (distances[i, j] < minDistance)
                        {
                            cluster1    = i;
                            cluster2    = j;
                            minDistance = distances[i, j];
                        }
                    }
                }
            }

            float value1, value2;
            // select representative
            if (useBestPosition)
            {
                value1 = clusters[cluster1].bestCandidate.bestEvaluation;
                value2 = clusters[cluster2].bestCandidate.bestEvaluation;
            }
            else
            {
                value1 = clusters[cluster1].bestCandidate.evaluation;
                value2 = clusters[cluster2].bestCandidate.evaluation;
            }


            int best = (value1 > value2)? cluster1:cluster2;
            CandidateCluster newCluster = new CandidateCluster(clusters[best].bestCandidate);
            newCluster.maxDistance = distances[cluster1, cluster2];
            newCluster.children.Add(clusters[cluster1]);
            newCluster.children.Add(clusters[cluster2]);
            clusters[cluster1].parent = newCluster;
            clusters[cluster2].parent = newCluster;
            clusters.Add(newCluster);


            // remove clusters cluster1 and cluster2
            clusters.RemoveAt(cluster1);
            clusters.RemoveAt(cluster2);
        }

        if (clusters.Count > 0)
        {
            clustering = clusters [0];
        }
    }