Partitions a graph into clusters.
Use the Algorithm property to specify the clustering algorithm to use.

Set the PutNeighborlessVerticesInOneCluster property to true to put the graph's neighborless vertices into one cluster.

IMPORTANT NOTE: If PutNeighborlessVerticesInOneCluster is true, CalculateGraphMetrics removes any neighborless vertices from the graph that is passed to it.

Inheritance: GraphMetricCalculatorBase
        TryCalculateCliqueMotifs
        (
            IGraph oGraph,
            Int32 iNMinimum,
            Int32 iNMaximum,
            BackgroundWorker oBackgroundWorker,
            ICollection <Motif> oExistingMotifs,
            out ICollection <Motif> oMotifs
        )
        {
            Debug.Assert(oGraph != null);

            oMotifs = null;

            ClusterCalculator clusterCalculator = new ClusterCalculator();

            clusterCalculator.Algorithm = ClusterAlgorithm.Clique;
            ICollection <Community> communities;

            if (clusterCalculator.TryCalculateGraphMetrics(oGraph, oBackgroundWorker,
                                                           out communities))
            {
                Int32 iTotalOperations   = communities.Count;
                Int32 iCalculationsSoFar = 0;

                HashSet <Motif> currentCliqueMotifs = new HashSet <Motif>();

                Dictionary <IVertex, Motif> verticesAlreadyInMotifs =
                    new Dictionary <IVertex, Motif>();

                // Don't consider any vertices used by other motifs
                if (oExistingMotifs != null)
                {
                    iTotalOperations += oExistingMotifs.Count;

                    foreach (Motif existingMotif in oExistingMotifs)
                    {
                        if (!ReportProgressIfNecessary(iCalculationsSoFar, iTotalOperations,
                                                       oBackgroundWorker))
                        {
                            return(false);
                        }

                        // We don't need to consider fan motifs because they cannot overlap
                        if (!(existingMotif is FanMotif))
                        {
                            foreach (IVertex existingVertex in existingMotif.VerticesInMotif)
                            {
                                verticesAlreadyInMotifs.Add(existingVertex, existingMotif);
                            }
                        }
                    }
                }

                // Sort the found cliques by the number of vertices
                IOrderedEnumerable <Community> sortedCommunities =
                    communities.OrderByDescending(c => c.Vertices.Count);

                // Select the cliques in the order of their original size
                foreach (Community community in sortedCommunities)
                {
                    if (!ReportProgressIfNecessary(iCalculationsSoFar, iTotalOperations,
                                                   oBackgroundWorker))
                    {
                        return(false);
                    }

                    // Remove any overlapping vertices before considering the clique
                    List <IVertex> availableVertices = community.Vertices.Where(
                        v => !verticesAlreadyInMotifs.ContainsKey(v)).ToList();
                    // Ensure the clique passes our criteria
                    if (availableVertices.Count >= iNMinimum &&
                        availableVertices.Count <= iNMaximum)
                    {
                        CliqueMotif trimmedCliqueMotif = new CliqueMotif(availableVertices);
                        currentCliqueMotifs.Add(trimmedCliqueMotif);

                        foreach (IVertex cliqueVertex in trimmedCliqueMotif.VerticesInMotif)
                        {
                            verticesAlreadyInMotifs.Add(cliqueVertex, trimmedCliqueMotif);
                        }
                    }
                }

                SetCliqueMotifScale(currentCliqueMotifs);

                oMotifs = currentCliqueMotifs;
            }

            return(true);
        }
    TryCalculateCliqueMotifs
    (
        IGraph oGraph,
        Int32 iNMinimum,
        Int32 iNMaximum,
        BackgroundWorker oBackgroundWorker,
        ICollection<Motif> oExistingMotifs,
        out ICollection<Motif> oMotifs
    )
    {
        Debug.Assert(oGraph != null);

        oMotifs = null;

        ClusterCalculator clusterCalculator = new ClusterCalculator();
        clusterCalculator.Algorithm = ClusterAlgorithm.Clique;
        ICollection<Community> communities;
         
        if ( clusterCalculator.TryCalculateGraphMetrics(oGraph, oBackgroundWorker,
            out communities) )
        {


            Int32 iTotalOperations = communities.Count;
            Int32 iCalculationsSoFar = 0;

            HashSet<Motif> currentCliqueMotifs = new HashSet<Motif>();

            Dictionary<IVertex, Motif> verticesAlreadyInMotifs =
                new Dictionary<IVertex, Motif>();

            // Don't consider any vertices used by other motifs
            if (oExistingMotifs != null)
            {
                iTotalOperations += oExistingMotifs.Count;

                foreach (Motif existingMotif in oExistingMotifs)
                {
                    if (!ReportProgressIfNecessary(iCalculationsSoFar, iTotalOperations,
                        oBackgroundWorker))
                    {
                        return (false);
                    }

                    // We don't need to consider fan motifs because they cannot overlap
                    if (!(existingMotif is FanMotif))
                    {
                        foreach (IVertex existingVertex in existingMotif.VerticesInMotif)
                        {
                            verticesAlreadyInMotifs.Add(existingVertex, existingMotif);
                        }
                    }
                }
            }

            // Sort the found cliques by the number of vertices
            IOrderedEnumerable<Community> sortedCommunities = 
                communities.OrderByDescending(c => c.Vertices.Count);

            // Select the cliques in the order of their original size
            foreach (Community community in sortedCommunities)
            {
                if (!ReportProgressIfNecessary(iCalculationsSoFar, iTotalOperations,
                    oBackgroundWorker))
                {
                    return (false);
                }

                // Remove any overlapping vertices before considering the clique
                List<IVertex> availableVertices = community.Vertices.Where(
                    v => !verticesAlreadyInMotifs.ContainsKey(v)).ToList();
                // Ensure the clique passes our criteria
                if (availableVertices.Count >= iNMinimum && 
                    availableVertices.Count <= iNMaximum)
                {
                    CliqueMotif trimmedCliqueMotif = new CliqueMotif(availableVertices);
                    currentCliqueMotifs.Add(trimmedCliqueMotif);

                    foreach (IVertex cliqueVertex in trimmedCliqueMotif.VerticesInMotif)
                    {
                        verticesAlreadyInMotifs.Add(cliqueVertex, trimmedCliqueMotif);
                    }
                }
            }

            SetCliqueMotifScale(currentCliqueMotifs);

            oMotifs = currentCliqueMotifs;
        }

        return (true);
    }