示例#1
0
 public UndirectedGraph(ImmutableArray <HashSet <Vertex> > adjacencies)
 {
     for (int i = 0; i < adjacencies.Length; ++i)
     {
         var v = Vertex.Nth(i);
         foreach (var w in adjacencies[v.index])
         {
             Debug.Assert(v != w);
             Debug.Assert(adjacencies[w.index].Contains(v));
         }
     }
     itsAdjacencies = adjacencies;
 }
示例#2
0
        // Iterate connected vertices, lowest degree first.
        // drop=N: omit last N vertices
        public static IEnumerable <Vertex> Ordering(UndirectedGraph graph, int drop)
        {
            Debug.Assert(drop >= 0);
            const int NO_PRIORITY = -1;

            int[] priorityPerVertex = new int[graph.Order];
            var   maxPriority       = 0;
            var   numLeftToPick     = 0;

            foreach (int i in Enumerable.Range(0, graph.Order))
            {
                var c      = Vertex.Nth(i);
                var degree = graph.Degree(c);
                if (degree > 0)
                {
                    var priority = degree;
                    maxPriority          = Math.Max(maxPriority, priority);
                    priorityPerVertex[i] = degree;
                    numLeftToPick       += 1;
                }
            }

            // Possible values of priority_per_vertex:
            //   no_priority: when yielded or if unconnected
            //   0..maxPriority: candidates still queued with priority (degree - #of yielded neighbours)
            var q = new PriorityQueue(maxPriority);

            foreach (var(c, p) in priorityPerVertex.Select((p, i) => (Vertex.Nth(i), p)))
            {
                if (p > 0)
                {
                    q.Put(priority: p, element: c);
                }
            }

            numLeftToPick -= drop;
            while (numLeftToPick >= 0)
            {
                numLeftToPick -= 1;
                var i = q.Pop();
                while (priorityPerVertex[i.index] == NO_PRIORITY)
                {
                    // was requeued with a more urgent priority and therefore already picked
                    i = q.Pop();
                }
                Debug.Assert(priorityPerVertex[i.index] >= 0);
                priorityPerVertex[i.index] = NO_PRIORITY;
                yield return(i);

                foreach (var v in graph.Neighbours(i))
                {
                    var oldPriority = priorityPerVertex[v.index];
                    if (oldPriority != NO_PRIORITY)
                    {
                        // Since this is an unvisited neighbour of a vertex just being picked,
                        // its priority can't be down to the minimum.
                        Debug.Assert(oldPriority > 0);
                        // Requeue with a more urgent priority, but don't bother to remove
                        // the original entry - it will be skipped if it's reached at all.
                        priorityPerVertex[v.index] = oldPriority - 1;
                        q.Put(priority: oldPriority - 1, element: v);
                    }
                }
            }
        }
示例#3
0
        public static void Visit(UndirectedGraph graph, IReporter reporter, Choice choice,
                                 ISet <Vertex> candidates, ISet <Vertex> excluded,
                                 ImmutableArray <Vertex> cliqueInProgress)
        {
            Debug.Assert(candidates.All(v => graph.Degree(v) > 0));
            Debug.Assert(excluded.All(v => graph.Degree(v) > 0));
            Debug.Assert(!candidates.Overlaps(excluded));
            Debug.Assert(candidates.Count >= 1);
            if (candidates.Count == 1)
            {
                // Same logic as below, stripped down
                var v          = candidates.First();
                var neighbours = graph.Neighbours(v);
                if (CollectionsUtil.AreDisjoint(neighbours, excluded))
                {
                    reporter.Record(CollectionsUtil.Append(cliqueInProgress, v));
                }

                return;
            }

            Vertex pivot;
            var    remainingCandidates     = new Vertex[candidates.Count];
            var    remainingCandidateCount = 0;
            // Quickly handle locally unconnected candidates while finding pivot
            const int INVALID = int.MaxValue;

            pivot = Vertex.Nth(INVALID);
            var seenLocalDegree = 0;

            foreach (var v in candidates)
            {
                var neighbours  = graph.Neighbours(v);
                var localDegree = CollectionsUtil.IntersectionSize(neighbours, candidates);
                if (localDegree == 0)
                {
                    // Same logic as below, stripped down
                    if (CollectionsUtil.AreDisjoint(neighbours, excluded))
                    {
                        reporter.Record(CollectionsUtil.Append(cliqueInProgress, v));
                    }
                }
                else
                {
                    if (seenLocalDegree < localDegree)
                    {
                        seenLocalDegree = localDegree;
                        pivot           = v;
                    }
                    remainingCandidates[remainingCandidateCount] = v;
                    remainingCandidateCount += 1;
                }
            }
            if (seenLocalDegree == 0)
            {
                return;
            }

            Debug.Assert(pivot.index != INVALID);
            if (choice == Choice.MaxDegreeLocalX)
            {
                foreach (var v in excluded)
                {
                    var neighbours  = graph.Neighbours(v);
                    var localDegree = CollectionsUtil.IntersectionSize(neighbours, candidates);
                    if (seenLocalDegree < localDegree)
                    {
                        seenLocalDegree = localDegree;
                        pivot           = v;
                    }
                }
            }

            for (var i = 0; i < remainingCandidateCount; ++i)
            {
                var v          = remainingCandidates[i];
                var neighbours = graph.Neighbours(v);
                Debug.Assert(neighbours.Any());
                if (!neighbours.Contains(pivot))
                {
                    var removed = candidates.Remove(v);
                    Debug.Assert(removed);
                    var neighbouringCandidates = CollectionsUtil.Intersection(neighbours, candidates);
                    if (neighbouringCandidates.Any())
                    {
                        var neighbouringExcluded = CollectionsUtil.Intersection(neighbours, excluded);
                        Visit(graph, reporter, choice,
                              neighbouringCandidates, neighbouringExcluded,
                              CollectionsUtil.Append(cliqueInProgress, v));
                    }
                    else if (CollectionsUtil.AreDisjoint(neighbours, excluded))
                    {
                        reporter.Record(CollectionsUtil.Append(cliqueInProgress, v));
                    }
                    var added = excluded.Add(v);
                    Debug.Assert(added);
                }
            }
        }