code: double silhouetteCoefficient(Map<Integer,Iterable<double[]>> clusterPointsByID) {
      double totalSilhouetteCoefficient = 0.0;
      long sampleCount = 0L;
  
      for (Map.Entry<Integer, Iterable<double[]>> entry : clusterPointsByID.entrySet()) {
        List<double[]> clusteredPoints = iterableToList(entry.getValue());
        long clusterSize = clusteredPoints.size();
        // Increment the total sample count for computing silhouette coefficient
        sampleCount += clusterSize;
        // if there's only one element in a cluster, then assume the silhouetteCoefficient for
        // the cluster = 0, this is an arbitrary choice per Section 2: Construction of Silhouettes
        // in the referenced paper
        if (clusterSize > 1) {
          for (double[] point : clusteredPoints) {
            double pointIntraClusterDissimilarity = clusterDissimilarityForPoint(point, clusteredPoints, true);
            double pointInterClusterDissimilarity =
                minInterClusterDissimilarityForPoint(entry.getKey(), point, clusterPointsByID);
            totalSilhouetteCoefficient += silhouetteCoefficient(
                pointIntraClusterDissimilarity, pointInterClusterDissimilarity);
          }
        }
  
      }
  
      return sampleCount == 0 ? 0.0 : totalSilhouetteCoefficient / sampleCount;
    }
docs: Computes the Silhouette Coefficient for this clustering.
  See https://en.wikipedia.org/wiki/Silhouette_(clustering)
  
  @param clusterPointsByID map of cluster ID to points that map to that cluster,
  for whom Silhouette coefficient needs to be computed
  @return Silhouette Coefficient in range [-1,1]; higher is better