示例#1
0
        /// <summary>
        /// Compute Smith and Schwartz sets with Tarjan's Algorithm.
        /// Thread safe.
        /// </summary>
        /// <param name="withdrawn">Candidates to ignore during computation.</param>
        /// <param name="set">The set to compute.</param>
        private IEnumerable <Candidate> ComputeSets(IEnumerable <Candidate> withdrawn, TopCycleSets set)
        {
            Dictionary <Candidate, int>    linkId;
            Dictionary <Candidate, int>    nodeId;
            HashSet <HashSet <Candidate> > stronglyConnectedComponents;
            Stack <Candidate> s;
            int i = 0;

            void dfs(Candidate c, bool isSmith)
            {
                // skip withdrawn candidates
                if (withdrawn.Contains(c))
                {
                    return;
                }
                // Only search if not yet visited.
                if (nodeId.ContainsKey(c))
                {
                    return;
                }
                // put onto the stack
                s.Push(c);
                // Set the node's linkId and nodeId, then increment i
                nodeId[c] = i;
                linkId[c] = i;
                i++;

                // Visit each neighbor
                HashSet <Candidate> neighbors = graph.Wins(c).Except(withdrawn).ToHashSet();

                if (isSmith)
                {
                    neighbors.UnionWith(graph.Ties(c).Except(withdrawn));
                }

                foreach (Candidate d in neighbors)
                {
                    // Visit first so it will be on the stack when we do the next check,
                    // unless it's already visited and thus won't be on the stack.
                    if (!nodeId.ContainsKey(d))
                    {
                        dfs(d, isSmith);
                        linkId[c] = Math.Min(linkId[c], linkId[d]);
                    }
                    // It's on the stack, so set linkId to the nodeId
                    else if (s.Contains(d))
                    {
                        linkId[c] = Math.Min(linkId[c], nodeId[d]);
                    }
                }
                // We've visited all neighbors, did we find a SCC?
                if (linkId[c] == nodeId[c])
                {
                    // move this SCC from the stack to our list of SCCs
                    HashSet <Candidate> scc = new HashSet <Candidate>();
                    do
                    {
                        scc.Add(s.Pop());
                    } while (!scc.Contains(c));
                    stronglyConnectedComponents.Add(scc);
                }
            }

            HashSet <Candidate> getSet(bool isSmith)
            {
                linkId = new Dictionary <Candidate, int>();
                nodeId = new Dictionary <Candidate, int>();
                s      = new Stack <Candidate>();
                stronglyConnectedComponents = new HashSet <HashSet <Candidate> >();
                i = 0;
                // Visit each node in the graph as a starting point, ignoring withdrawn candidates
                foreach (Candidate c in graph.Candidates.Except(withdrawn))
                {
                    dfs(c, isSmith);
                }

                // Find every SCC that cannot be reached by any other SCC.
                // In the Smith Set, this is one SCC; in the Schwartz Set,
                // we may have several.
                Dictionary <(HashSet <Candidate>, HashSet <Candidate>), bool> reachable
                    = new Dictionary <(HashSet <Candidate>, HashSet <Candidate>), bool>();
                HashSet <HashSet <Candidate> > dominating = new HashSet <HashSet <Candidate> >();
                HashSet <Candidate>            output     = new HashSet <Candidate>();

                Dictionary <Candidate, Dictionary <(HashSet <Candidate>, HashSet <Candidate>), bool> > subsets
                    = new Dictionary <Candidate, Dictionary <(HashSet <Candidate>, HashSet <Candidate>), bool> >();

                // Special thanks to https://stackoverflow.com/a/55526085/5601193
                // This is the slowest thing in here, but there's no faster algorithm known.
                void ParallelFloydWarshall()
                {
                    // Thread safety:
                    //   reads:
                    //     one index in subsets[], linkId, withdrawn, stronglyConnectedComponents
                    //   calls:
                    //     graph.Candidates, graph.Losses, graph.Wins
                    Dictionary <(HashSet <Candidate>, HashSet <Candidate>), bool> DirectCheck(Candidate l)
                    {
                        Dictionary <(HashSet <Candidate>, HashSet <Candidate>), bool> rset
                            = subsets[l];
                        HashSet <Candidate> sccl = stronglyConnectedComponents.Where(x => x.Contains(l)).Single();

                        foreach (Candidate m in linkId.Keys.Except(withdrawn))
                        {
                            HashSet <Candidate> sccm = stronglyConnectedComponents.Where(x => x.Contains(m)).Single();

                            // The SCC containing (l) can reach the SCC containing (m) if
                            //  - (l) is already known to reach (m)
                            if (!rset.ContainsKey((sccl, sccm)))
                            {
                                rset[(sccl, sccm)] = false;
                            }
示例#2
0
 public TopCycle(BallotSet ballots, TopCycleSets set = TopCycleSets.smith)
     : this(new PairwiseGraph(ballots))
 {
 }
示例#3
0
 public IEnumerable <Candidate> GetTopCycle(IEnumerable <Candidate> withdrawn, TopCycleSets set)
 => ComputeSets(withdrawn, set);
示例#4
0
 public TopCycle(PairwiseGraph graph, TopCycleSets set = TopCycleSets.smith)
 {
     defaultSet = set;
     this.graph = graph;
 }